:string
, :number
등과 같이 고정된 타입이 아닌 사용에 따라 여러 타입을 사용하게 해준다는 것이다.any
타입과 흡사하지만 타입의 정보가 동적으로 결정된다는 차이가 있다.function helloString(message: String): String { return message; } function helloNumber(message: Number): Number { return message; } // 모든 타입으로 받거나 리턴할 수 있도록 하려면? function hello(message: any): any { return message; } // 어떤 것도 들어올 수 있으므로 any로 인식함 console.log(hello("Mark").length); console.log(hello(39).length); // 컴파일 타임에는 문제가 없지만 런타임에서 문제 발생 // generic function helloGeneric<T>(message: T): T { return message; } console.log(helloGeneric("Mark").length); console.log(helloGeneric(39)); console.log(helloGeneric(true));
- 제너릭은
<>
기호를 이용해서 정의하며, 이름은 자유롭게 지정할 수 있다.- ex> function 함수이름 <제너릭이름>(인수: 제너릭 이름) : 제너릭 이름 {}
function helloBasic<T, U>(message: T, comment: U): T { return message; } // 제네릭 타입 명시 helloBasic<String, Number>("Mark", 39); // 반환타입 String, Number // 제네릭 타입 추론 helloBasic(36, 39); // 반환타입 36, 39
Array
function helloArray<T>(message: T[]): T { return message[0]; } helloArray(["Hello", "World"]); // 반환타입 string helloArray(["Hello", 5]); // 반환타입 string | number
Tuple
function helloTuple<T, K>(message: [T, K]): T { return message[0]; } helloTuple(["Hello", "World"]); // 반환타입 string helloTuple(["Hello", 5]); // 반환타입 string
type alias
type HelloFunctionGeneric1 = <T>(message: T) => T; const helloFunction1: HelloFunctionGeneric1 = <T>(message: T): T => { return message; }
interface
interface HelloFunctionGeneric2 { <T>(message: T): T; } const helloFunction2: HelloFunctionGeneric2 = <T>(message: T): T => { return message; }
class Person<T, K> { // 제네릭의 유효범위는 클래스 전체 범위 안 private _name: T; private _age: K; constructor(name: T, age: K) { this._name = name; this._age = age; } } // 타입 추론 new Person("Mark", 39); // 타입 명시 new Person<string, number>("Mark", 39);
class PersonExtends<T extends String | Number> { // string, number만 가능 private _name: T; constructor(name: T) { this._name = name; } } new PersonExtends("Mark"); new PersonExtends(39); // new PersonExtends(true); // 컴파일 에러 // 제한을 통해 이 코드의 제 3자에게 올바른 가이드라인 제공
keyof
키워드를 붙여 객체 키 이름들의 유니온 타입 반환keyof
는 Object
의 key
들의 lieteral
값들을 가져온다.interface IPerson { name: String; age: Number; } const person: IPerson = { name: "Mark", age: 39, }; // 지정된 객체의 키의 이름들의 유니온 타입 keyof IPerson // 'name' | 'age'
keyof
사용전: 매개변수key
타입에 따른 리턴값 지정이 정확히 안됨function getProp(obj: IPerson, key: 'name' | 'age'): string | number { return obj[key]; }
keyof
사용후: 리턴타입이 아직도 유니온 타입이다.function getProp(obj: IPerson, key: keyof IPerson): IPerson[keyof IPerson] { return obj[key]; } // IPerson[keyof IPerson] // => IPerson["name" | age] // => IPerson["name"] | IPerson["age"] // => String | Number
제네릭 적용
// 프로퍼티의 값을 가져오는 함수 function getProp<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } console.log(getProp(person, 'name')); // Mark console.log(getProp(person, 'age')); // 39 // 프로퍼티의 값을 설정하는 함수 function setProp<T, K extends keyof T>(obj: T, key: K, value: T[K]): void { obj[key] = value; } setProp(person, "name", "Anna"); setProp(person, "age", 24); console.log(getProp(person, 'name')); // Anna console.log(getProp(person, 'age')); // 24