07.TS Generic
Updated:
TS Generic
1.Generics, Any 와 다른점
- 타입을 다 받기 위해 Any 를 사용하게 되면 아래의 코드와 같이 error 가 발생 됩니다.
function helloString(message: string): string {
return message;
}
function helloNumber(message: number): number {
return message;
}
// 위와 같이 반복적인 함수들 이 발생되는데.. 그래서 범용적으로 사용하기 위해서 any 를 사용할 때,
// any 를 사용하게 되면 발생되는 문제
function hello(message: any): any {
return message;
}
// 출력은 잘 되지만 추가로 매서드를 사용할 때, error 가 발생됨
console.log(hello("Jacob"));
console.log(hello(80));
// error (str 에 사용할 수 있는 .length 를 hello() 가 any 이기 때문에 사용할 수 없음)
console.log(hello("Jacob").length);
🔶 그래서 Generic
을 사용하게 됨으로 위와 같은 문제를 해결 할 수 있습니다.
function helloGeneric<T>(message: T): T {
return message;
}
// message 가 'Jacob' 이라는 literal 형식이 그냥 type 이 되버리는것 -> Generic
console.log(helloGeneric("Jacob"));
// 그렇기 때문에 추가로 .method 사용이 가능해 짐 (any 와 다른 점!!)
console.log(helloGeneric("Jacob").length);
// 이번엔 type 이 number 형태인 80 이 되기 때문에 .숫자관련 method 를 사용할 수 있음
console.log(helloGeneric(80));
// 타입이 true 라는 boolean 타입으로 사용할 수 있음.
console.log(helloGeneric(true));
- Generic 장점 : 타입으로 된 연산이 내부 함수 내에서 사용이 가능하게 됨 (any 와 다른점임 !!)
2.Generic Basic
function helloBasic<T>(message: T): T {
return message;
}
// 직접 generic 에 type 을 지정해서 사용하는 방법 -> 넣고 사용하면 뒤에값이 명시된 type 과 같아야 하고,
helloBasic<string>("Jacob");
// 위에 <T> 가 값을 추론해서 <T> 가 number 임을 추측해서 사용됨 -> 않널고 쓰면 뒤에 값에따라 알아서 추론되서 사용됨
helloBasic(80);
// generic 을 여러개 사용한 경우
function helloBasic2<T, U>(message: T, comment: U): T {
return message;
}
// T 는 string 이라고 명시, U 는 number 임을 명사 그러면 뒤에는 string, number 형태의 값이 와야 함
helloBasic2<string, number>("Jacob", 80);
// 명시를 안하고 넣을때는 알아서 두개다 number 로 추론됨. T 와 U 는 number type 으로 추론되서 사용됨 (단, <T, U> 를 넣었기 때문에 반드시. 2개의 값으로 있어야 함)
helloBasic2(36, 39);
3.Generic array & tuple
// generic array
function helloArray<T>(message: T[]): T {
return message[0];
}
// 2개다 string 일 경우, 둘다 str 로 추론 되어 type 이 지정됨
helloArray(["Hello", "world"]);
// 자동으로 추론 되어 string | number 이렇게 union type 으로 지정됨
helloArray(["hello", 5]);
// generic tutple
function helloTuple<T, K>(message: [T, K]): T {
return message[0];
}
// array 와 마찬가지로 둘 다 str 으로 받아서 사용됨
helloTuple(["Hello", "world"]);
// 근데 정확하게 0 번 째 index 가 str 으로 추론 됨에 따라 .length 같은 함수를 사용할 수 있음
helloTuple(["Hello", 5]);
4.Generic Function
// generic alias
type HelloFunctionGeneric1 = <T>(message: T) => T;
const helloFunction1: HelloFunctionGeneric1 = <T>(message: T): T => {
return message;
};
// generic interface
interface HelloFunctionGeneric2 {
<T>(message: T): T;
}
const helloFunction2: HelloFunctionGeneric2 = <T>(message: T): T => {
return message;
};
// 기존의 alias, interface 형식에다가 그냥 generic 만 추가한 형태임
5.Generic class
// generic class
class Person<T, K> {
private _name: T;
private _age: K;
constructor(name: T, age: K) {
this._name = name;
this._age = age;
}
}
new Person("Jacob", 39);
// str 으로 지정하고 number 를 넣기 때문에 error
new Person<string>(39);
// T, K 를 str , number 로 지정했기 때문에 맞춰서 나와야 함
new Person<string, number>("Jacob", "age");
6.Generic with extends
class
에서 사용되는extends
는 상속의 개념이지만generic
에서는 좀 다른 의미를 자지고 있습니다.
// generic extends
// 특정 타입만 사용이 가능하다고 명시하는것임 즉, T 는 string 또는 number type 만이 될 수 있다
// Type 을 사용할때 , 가능한 가장 작은범위를 사용해서 이용하는 것이 나중에 컴파일 할때 error 를 줄일 수 있다.
// generic type 을 사용 할 때는 extends 키워드를 사용하는 것을 추천 (그나마, type 의 범위를 줄여서 사용 할 수 있기 때문)
class PersonExtends<T extends string | number> {
private _name: T;
constructor(name: T) {
this._name = name;
}
}
// T 에 string 이 있으니까 ture
new PersonExtends("Jacob");
// T 에 number 가 있으니까 true
new PersonExtends(80);
// T 에 boolean 이 없으니까 false
new PersonExtends(true);
7.keyof & type lookup system
- keyof 와 generic 을 이용해서 type 을 찾아내는 시스템을 만드는것 (타입을 정확하게 찾아내는 방식임)
interface IPerson {
name: string;
age: number;
}
const person: IPerson = {
name: "Jacob",
age: 80,
};
// keyof 타입 앞에 붙여서 새로운 타입을 만들어 내는 것임
type Keys = keyof IPerson;
const Keys: Keys = "age";
// IPerson[keyof Iperson]
// => Iperson["name" | "age"]
// => Iperson["name"] | Iperson["age"]
// => string | number
// generic 사용
// K는 keyof T 에 의 해 재한된 형태 라는 것임
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
getProp(person, "name");
function setProp<T, K extends keyof T>(obj: T, key: K, value: T[K]): void {
obj[key] = value;
}
setProp(person, "name", "John");
🔶 🔷 📌 🔑
Reference
-
TypeScript Deep Dive - https://basarat.gitbook.io/typescript/project/compilation-context
-
TypeScript - https://www.typescriptlang.org/
-
HEROPY Tech - https://heropy.blog/2020/01/27/typescript/
-
DailyEngineering - https://hyunseob.github.io/2017/01/14/typescript-generic/
Leave a comment