코드가 수행될 때 타입이 명시된다.
코드를 작성할 때는 식별자(T,U,V)를 사용해 타입이 아직 정해지지 않은 상태이다.
제네릭을 사용하게 되면 재사용성이 높은 함수와 클래스를 생성할 수 있다.
제네릭도 타입을 미리 지정하지는 않지만 any를 사용하지 않기 때문에 컴파일 단계에서 타입을 체크할 수 있다.
function sort<T>(items: T[]): T[] {
return items.sort();
}
const nums = [1, 2, 3, 4];
const chars = ["a", "b", "c", "d"];
sort<number>(nums);
sort<string>(chars);
class Queue<T> {
protected data: Array<T> = [];
push(item: T) {
this.data.push(item);
}
pop(): T | undefined {
return this.data.shift();
}
}
const numberQueue = new Queue<number>();
numberQueue.push('a') // Argument of type 'string' is not assignable to parameter of type 'number'
union type으로 작성하면 두 type을 공통적으로 포함하는 메서드만 사용 가능하다.
const printMessage = (message: string|number) => {
return message
}
const message1 = printMessage("hello")
message1.length; // Property 'length' does not exist on type 'number'.
임의의 타입이 아닌 특정 제약 안에서 할당 할 수 있게 한다.
const printMessage = <T extends string | number>(message: T): T => {
return message;
};
const message1 = printMessage(true);
// Argument of type 'boolean' is not assignable to parameter of type 'string | number'.
object의 키 값으로 type을 한정할 수 있다.
const getProperty = <T extends object, U extends keyof T>(obj: T, key: U) =>
obj[key];
getProperty({a:1, b:2}, "a") // 1
getProperty({a:1, b:2}, "c")
// argument of type '"c"' is not assignable to parameter of type '"a" | "b"'.