제네릭은 함수나 클래스의 선언 시점이 아닌 사용 시점에 타입을 선언할 수 있는 방법을 제공한다!
제네릭을 사용하면 함수, 클래스 , 인터페이스를 다양한 타입으로 재사용할 수 있다.
선언할 때는 type 파라미터만 적어주고 생성하는 시점에 사용할 타입을 결정
예제를 보면서 확인해보자!!
function getSize(arr):number {
return arr.length;
}
const arr1 = [1,2,3];
getSize(arr1); //3출력
위처럼 작성하면 에러남
아래와 같이 타입을 명시해주면 에러 해!결!
function getSize(arr: number[]):number {
return arr.length;
}
const arr1 = [1,2,3];
getSize(arr1); //3출력
지금은 숫자 하나의 타입만 있지만 만약 문자나 불린, 객체까지 받으려고 한다면??
function getSize(arr: number[] | string[] | boolean[] | object[]):number {
return arr.length;
}
const arr1 = [1,2,3];
getSize(arr1); //3출력
const arr2 = ['a', 'b', 'c'];
getSize(arr2); //3
const arr3 = [false, true, true];
getSize(arr3); //3
const arr4 = [{}, {}, { name : "Tim" }];
getSize(arr4); //3
union으로 해줄 수 있지만 계속 길어지게 된다!!..(문제 발생)
이럴 때 쓸 수 있는 것이 바로바로 제네릭!! (해결책 등쟝)
위 코드가 아래와같이 변경 가능!
바로 사용시점(getSize를 불러올 때) 원하는 타입을 명시해주는 것!!
function getSize<T>(arr: T[]):number {
return arr.length;
}
const arr1 = [1,2,3];
getSize<number>(arr1); //3출력
const arr2 = ['a', 'b', 'c'];
getSize<string>(arr2); //3
const arr3 = [false, true, true];
getSize<boolean>(arr3); //3
const arr4 = [{}, {}, { name : "Tim" }];
getSize<object>(arr4); //3
타입스크립트는 똑똑하기 때문에 <number>나 <string>을 써주지 않아도 타입 추론을 통해 타입을 추론해준다.
실제로 잘 추론하고 콘솔에도 잘 찍히는 것을 확인할 수 있다
이번에는 인터페이스 예제를 통해 확인해보자
interface Mobile<T> {
name: string;
price: number;
option: T;
};
const m1: Mobile<object> = {
name: "s21",
price:1000,
option: {
color: "red",
coupon: false,
},
};
//타입이 지정되어있다면 아래처럼 작성 가능
const m1: Mobile<{color : string; coupon : boolean}> = {
name: "s21",
price:1000,
option: {
color: "red",
coupon: false,
},
};
const m2: Mobile<string> = {
name: "s20",
price: 900,
option: "good",
};
***근데 여기서는 <string>과 같이 타입명시를 해주어야 오류가 나지 않는다. 여기서 타입스크립트는 타입추론이 불가..?
콘솔에는 찍히지만 위에처럼 추론을 해주지 못한다.
Q. 왜 그럴까??
A. 인터페이스를 사용했기 때문에 정확한 인터페이스의 타입을 제공해줘야 한다!!
위에 추론을 한 코드는 단순 array string이라 타입추론이 가능했던 것!!
제약 조건(Constraints)
타입 변수 T가 한정된 타입만 허용하려면 extends 키워드를 사용하여 제약 조건을 만들 수 있다!
//제약 조건이 없을 때
interface MyType<T> {
name: string,
value: T
}
const dataA: MyType<string> = {
name: 'Data A',
value: 'Hello world'
};
const dataB: MyType<number> = {
name: 'Data B',
value: 1234
};
const dataC: MyType<boolean> = {
name: 'Data C',
value: true
};
const dataD: MyType<number[]> = {
name: 'Data D',
value: [1, 2, 3, 4]
};
//제약 조건이 있을 때
interface MyType<T extends string | number> {
name: string,
value: T
}
const dataA: MyType<string> = {
name: 'Data A',
value: 'Hello world'
};
const dataB: MyType<number> = {
name: 'Data B',
value: 1234
};
const dataC: MyType<boolean> = { // TS2344: Type 'boolean' does not satisfy the constraint 'string | number'.
name: 'Data C',
value: true
};
const dataD: MyType<number[]> = { // TS2344: Type 'number[]' does not satisfy the constraint 'string | number'.
name: 'Data D',
value: [1, 2, 3, 4]
};
조건부 타입(Conditional Types)
조건부 타입이란 '타입 구현' 영역에서 사용하는 extends가 삼항 연산자를 사용할 때를 말한다!!
// `T`는 `boolean` 타입으로 제한.
interface IUser<T extends boolean> {
name: string,
age: T extends true ? string : number, // `T`의 타입이 `true`인 경우 `string` 반환, 아닌 경우 `number` 반환.
isString: T
}
const str: IUser<true> = {
name: 'Neo',
age: '12', // String
isString: true
}
const num: IUser<false> = {
name: 'Lewis',
age: 12, // Number
isString: false
}
삼항 연산자 연속 사용도 가능!
type MyType<T> =
T extends string ? 'Str' :
T extends number ? 'Num' :
T extends boolean ? 'Boo' :
T extends undefined ? 'Und' :
T extends null ? 'Nul' :
'Obj';
출처
https://www.youtube.com/watch?v=pReXmUBjU3E
goorm
구름은 클라우드 기술을 이용하여 누구나 코딩을 배우고, 실력을 평가하고, 소프트웨어를 개발할 수 있는 클라우드 소프트웨어 생태계입니다.
www.goorm.io
'Typescript' 카테고리의 다른 글
tsconfig에서 allowSyntheticDefaultImports flug (0) | 2024.08.06 |
---|---|
[타입스크립트]Optional - 매개변수, 속성과 메소드, 체이닝, 널 병합 연산자 (0) | 2022.04.10 |
[타입스크립트]인터페이스 (0) | 2022.04.08 |
[타입스크립트]타입 추론(Inference)과 타입 단언(Assertions) (0) | 2022.04.06 |
[타입스크립트] Void, Never , Union , Intersection ,Function (0) | 2022.04.06 |