class DuplicatedGenericName<T> {
sayHello<T>(logTime: T) {
console.log(`logTime: ${typeof logTime}`);
}
}
const duplicated = new DuplicatedGenericName<string>(); // 클래스의 제너릭은 string
duplicated.sayHello<number>(123); // 메서드는 number
클래스의 제너릭과 메서드의 제너릭이 동시에 같은 이름으로 선언이 되면 메서드의 제너릭을 따라간다. 즉 DuplicatedGenericName의 T는 어디에서도 쓰이지 않는다.
따라서 헷갈리지 않도록 클래스 제너릭과 메서드 제너릭의 이름을 서로 다르게 선언하자.
interface Singer<T, V> {
name: T;
sing(year: V): void;
}
// #1
// Singer을 implement 했기 때문에 class 안데 Singer의 프로퍼티, 메소드들이 다 존재해야 한다.
class Idol implements Singer<string, number> {
name: string;
constructor(name: string) {
this.name = name;
}
sing(year: number): void {
console.log(`${year} ${this.name}이 노래를 부른다.`);
}
}
const yujin = new Idol('안유진');
yujin.sing(2003);
Idole 클래스는 Singer 타입을 implement 했기 때문에 Singer의 프로퍼티와 함수가 Idol에 존재해야 한다.
위처럼 인터페이스에 제너릭 타입을 줄 수도 있고, 아래처럼 인스턴스를 생성할 때 제너릭 타입을 줄 수 있다.
class Idol2<T, V> implements Singer<T, V> {
name: T;
constructor(name: T) {
this.name = name;
}
sing(year: V): void {
console.log(`${year} ${this.name}이 노래를 부른다.`);
}
}
const yuna = new Idol2<string, number>('윤아');
yuna.sing(1990);
가장 많이 사용하게 될 방식 중 하나다.
const afterTwoSeconds = function () {
return new Promise((resolve) => {
setTimeout(() => {
resolve('done');
}, 2000);
});
};
const runner = async function () {
const res = await afterTwoSeconds(); // unknown 타입이 나옴, 좀 불쾌함. resolve에서 'done'이라는 string을 받게 하고 싶다.
console.log(res);
};
runner();
afterTwoSeconds 함수는 2초 뒤에 'done' 문자열을 출력하는 Promise를 반환한다. 하지만 runner에서 비동기적으로 실행하면 afterTwoSeconds 함수는 unknown 타입을 리턴한다. 우리가 원하는 타입을 리턴하려면 어떻게 해야 할까?
const afterOneSecond = function (): Promise<string> {
return new Promise((resolve) => {
setTimeout(() => {
resolve('done');
}, 1000);
});
};
const runner2 = async function () {
const res = await afterOneSecond(); // type: string
console.log(res);
};
runner2();
Promise 타입에 제너릭 타입을 우리가 원하는 타입을 주면 된다.