TypeScript의 Generics<T>

Jane Yeonju Kim·2023년 3월 1일
0

TypeScript

목록 보기
2/2
post-thumbnail
post-custom-banner




제네릭의 의미

제네릭이란 다양한 타입에서도 동작하는 컴포넌트를 의미한다.
any 대신에 Type을 사용하면 타입 추론이 가능하고 확장이 가능한 구조로 만들 수 있다.
<>꺽쇠 안에 타입 이름을 적어주면 되는데 보통 <T>를 사용한다.(이 글에서는 <Type>을 사용)

  • any와 Type의 비교 :
/*  
	인자로 받은 타입을 재사용할 수 없음
	반환할 타입을 인자로 받은 타입(arg)과 똑같이 지정할 수가 없음!
*/
function identity(arg: any): any {
  return arg;
}

// 인자로 받은 타입을 그대로 반환하여 다시 사용할 수 있음 
function identity<Type>(arg: Type): Type {
  return arg;
}
  • 타입 추론 :
function identity<Type>(arg: Type): Type {
  return arg;
}

// 명시적인 타입 인수 전달
let explicitOutput = identity<string>("myString"); 

/* 
	타입 인수 추론
	컴파일러가 알아서 인자로 받은 타입을 추론함
*/
let typeArgumentInference = identity("myString");




제네릭 타입

  • 제네릭 함수를 타입으로 사용하기 :
// 제네릭 함수
function identity<Type>(arg: Type): Type {
  return arg;
}

/*
	제네릭 함수 타입
    타입이 함수 형식이고 이 형식에 맞는 함수를 이 변수에 넣어줄 수 있음
*/
let myIdentity: <Type>(arg: Type) => Type = identity;

// 반환 타입이 다른 함수를 myIdentity 변수에 넣어보는 예시
function notIdentityFunc<Type>(arg: Type): string {
  return "hi";
}

let myIdentity2: <Input>(arg: Input) => Input;
myIdentity2 = notIdentityFunc;  // 당연히 에러남 : Type '<Type>(arg: Type) => string' is not assignable to type '<Input>(arg: Input) => Input'.
//  Type 'string' is not assignable to type 'Input'.
//  'Input' could be instantiated with an arbitrary type which could be unrelated to 'string'.

/*
	제네릭 함수 타입을 호출 시그니처(call signature)로 사용하는 방법
    이 예시에서는 위의 myIdentity와 큰 차이가 없음
    이렇게 할거면 제네릭 인터페이스를 사용하는 것이 유리함
*/
let myIdentity3: { <Type>(arg: Type): Type } = identity;

호출 시그니처란 함수의 인자와 반환 타입을 미리 선언하는 것을 말하는데, 다형성과 관련이 있다. 호출 시그니처를 다르게 만들어두면, 다른 타입이 함수의 인자로 들어올 때 다르게 처리할 수 있다. 그런데 호출 시그니처를 제네릭 타입으로 사용하면 다양한 타입에 같은 처리를 하도록 구현할 수 있다.

  • 제네릭 인터페이스 :
// 제네릭 함수를 인터페이스로 빼서 재사용
interface GenericIdentityFn {
  <Type>(arg: Type): Type;
}
 
function identity<Type>(arg: Type): Type {
  return arg;
}
 
let myIdentity: GenericIdentityFn = identity;

타입으로 선언하는 대신 인터페이스를 사용하는 이유는 인터페이스는 extends를 통해 확장이 가능하기 때문이다. 그리고 인터페이스는 같은 이름으로 다시 선언을 하면 자동으로 확장이 된다.




제네릭 클래스

// 클래스의 정적(static) 속성을 제네릭으로 사용해보는 예시
class GenericNumber<NumType> {
  zeroValue: NumType;
  add: (x: NumType, y: NumType) => NumType;
}
// 에러 : Property 'zeroValue' has no initializer and is not definitely assigned in the constructor. 
// 'add'도 같은 에러남

// 클래스의 instance를 생성해서 사용하면 에러가 나지 않음
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function (x, y) {
  return x + y;
};

console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));

클래스에서는 제네릭 타입을 static 속성에서는 사용할 수 없고 instance의 속성에서는 사용할 수 있다.








타입스크립트 핸드북
[Typescript] Call signature, Overloading, Generic
타입스크립트 type과 interface의 공통점과 차이점

profile
안녕하세요! 김개발자입니다 👩‍💻 🐈
post-custom-banner

0개의 댓글