StudyForYou / ouahhan-typescript-with-react

우아한 타입스크립트 with 리액트 스터디 레포 🧵
4 stars 0 forks source link

#16 [5장_1] extends의 3가지 사용법에 대해 설명해주세요. #28

Closed hyeyoonS closed 2 months ago

hyeyoonS commented 2 months ago

❓문제

extends의 3가지 사용법에 대해 설명해주세요.

🎯답변

1. interface 확장

interface Employee extends Person { employeeId: number; }

const employee: Employee = { name: 'John', age: 30, employeeId: 12345, };


### 2. 제네릭 타입에서 한정자
- 말 그대로 타입에 제한을 두어 특정 타입으로 좁힐 때 사용된다.
```ts
// Lengthwise 인터페이스는 length를 가지고 있으며, 이 속성의 타입은 number이다.
//이 인터페이스를 구현하는 모든 객체는 length 속성을 가져야 한다.
interface Lengthwise {
    length: number;
}

//타입 변수 T는 Lengthwise 인터페이스를 확장해야 한다.
// → T는 length라는 속성을 반드시 포함해야 한다!

//또, 함수의 매개변수 arg는length 속성을 가져야 한다.
function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length); // arg가 length 속성을 가지므로 arg.length를 출력한다.
    return arg; //T 타입을 반환 = 입력 타입과 동일한 타입을 반환함을 의미한다.
}

//loggingIdentity 함수는 length와 value 속성을 가진 객체를 인수로 받는다.
//이 객체는 length 속성을 가지고 있으므로 Lengthwise 인터페이스를 만족한다.
//따라서 함수 호출이 가능하다
loggingIdentity({ length: 10, value: 'Hello' }); // OK

//숫자 3을 인수로 받으려고 하지만, 이는 length 속성을 가지지 않으므로 오류
loggingIdentity(3); // Error: 숫자 타입에는 'length' 프로퍼티가 없습니다.

3. 타입 조건부 설정

interface Email { message: string; }

interface Dog { bark(): void; }

type EmailMessageContents = MessageOf; // string type DogMessageContents = MessageOf; // never

drizzle96 commented 2 months ago
  1. 인터페이스 확장 인터페이스의 타입을 확장할 때 사용할 수 있습니다.
    
    interface Animal {
    age: number
    }

interface Human extends Animal { name: string tall: number }


2. 제한된 제네릭
제네릭 자리에 사용하여 제네릭 타입에 제약 조건을 걸 수 있습니다. 
```ts
type MessageOf<T extends { message: unknown }> = T["message"];

interface Email {
  message: string;
}

 // string
type EmailMessageContents = MessageOf<Email>;
  1. 조건부 타입 삼항연산자를 사용해 조건에 따라 다른 타입이 계산되게 할 수 있습니다. 이를 통해 조건에 따라 사용자가 원하는 값으로 타입을 구체화할 수 있습니다.
    
    // 2번을 3번 형태로 바꾸면 MessageOf가 any 타입을 받을 수 있음
    type MessageOf<T> = T extends { message: unknown } ? T["message"] : never;

interface Email { message: string; }

interface Dog { bark(): void; }

// string type EmailMessageContents = MessageOf; // never type DogMessageContents = MessageOf;

hyeyoonS commented 2 months ago

1. interface에서 타입 확장

interface Person {
    name: string;
    age: number;
}

interface Employee extends Person {
    employeeId: number;
}

const employee: Employee = {
    name: 'John',
    age: 30,
    employeeId: 12345,
};

2. 타입 조건부 설정

T extends U ? X : Y
type CheckType<T> = T extends string ? 'String Type' : 'Non-String Type';

type TypeA = CheckType<string>; // 'String Type'
type TypeB = CheckType<number>; // 'Non-String Type'
type TypeC = CheckType<boolean>; // 'Non-String Type'
interface Bank {
    financialCode: string;
    companyName: string;
    name: string;
    fullName: string;
}

interface Card {
financialCode: string;
    companyName: string;
    name: string;
    appCardType?: string;
}

type PayMethod<T> = T extends "card" ? Card : Bank;
type CardPayMethodType = PayMethod<"card">;
type BankPayMethodType = PayMethod<"bank">;

3. 제네릭 타입에서 한정자

// Lengthwise 인터페이스는 length를 가지고 있으며, 이 속성의 타입은 number이다.
//이 인터페이스를 구현하는 모든 객체는 length 속성을 가져야 한다.
interface Lengthwise {
    length: number;
}

//타입 변수 T는 Lengthwise 인터페이스를 확장해야 한다.
// → T는 length라는 속성을 반드시 포함해야 한다!

//또, 함수의 매개변수 arg는length 속성을 가져야 한다.
function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length); // arg가 length 속성을 가지므로 arg.length를 출력한다.
    return arg; //T 타입을 반환 = 입력 타입과 동일한 타입을 반환함을 의미한다.
}

//loggingIdentity 함수는 length와 value 속성을 가진 객체를 인수로 받는다.
//이 객체는 length 속성을 가지고 있으므로 Lengthwise 인터페이스를 만족한다.
//따라서 함수 호출이 가능하다
loggingIdentity({ length: 10, value: 'Hello' }); // OK

//숫자 3을 인수로 받으려고 하지만, 이는 length 속성을 가지지 않으므로 오류
loggingIdentity(3); // Error: 숫자 타입에는 'length' 프로퍼티가 없습니다.