제네릭 클래스는 제네릭 인터페이스와 유사한 형태를 가지고있다.
class GenericNumber<NumType>{
zeroValue: NumType;
add: (x: NumType, y: NumType) => NumType;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
return x+y;
}
위 코드는 꽤 정확한 사용이지만 number타입을 써야만한다는 제약이 없다.
그렇기 때문에 아래와 같이 string을 사용 할 수 있다.
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function (x,y){
return x+y;
}
function loggingIdentity<Type>(arg: Type): Type {
console.log(arg.length); // Property 'length' does not exist on type 'Type'.
return arg;
}
위 코드 같은 경우 Type이 어떤 type인지 모르기 때문에 arg.length에서 에러가 난다. 이 경우 length를 가진 interface를 사용해주면 된다.
interface Lengthwise{
legnth: number;
}
function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
위와 같이 구성하면 length라는 프로퍼티가 없는 타입은 올 수 없다.
loggingIdentity(3);
Argument of type 'number' is not assignable to parameter of type 'Lengthwise'.
다른 타입 파라미터에 의해 제약되는 타입 파라미터를 정의할 수 있다.
function getProperty<Type, key extneds keyof Type>(obj: Type, key: Key) {
return obj[key];
}
let x { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a");
getProperty(x, "b");
getProperty(x, "d");
getProperty(x, "e"); // Argument of type '"e"' is not assignable to parameter of type '"a" | "b" | "c" | "d"'.
제네릭을 사용한 타입스크립트에서 팩토리를 만들때 생성자 함수를 통해 클래스의 타입을 참조해야한다.
function create<Type>(c: { new (): Type }): Type {
return new c();
}
class BeeKeeper {
hasMask: boolean = true;
}
class ZooKeeper {
nametag: string = "Mikle";
}
class Animal {
numLegs: number = 4;
}
class Bee extends Animal {
keeper: BeeKeeper = new BeeKeeper();
}
class Lion extends Animal {
keeper: ZooKeeper = new ZooKeeper();
}
function createInstance<A extends Animal>(c: new () => A): A {
return new c();
}
createInstance(Lion).keeper.nametag;
createInstance(Bee).keeper.hasMask;