Typescript 문서 - 06

Typescript 문서 - 06

Generics

C# 및 Java와 같은 언어에서 재사용 가능한 구성 요소를 작성하기 위한 기본 도구 중 하나가 Generic이다. 즉, 다양한 타입에서 작동할 수 있는 구성 요소를 만들 수 있어야 한다.

Hello World of Generics

함수를 정의할 때 모든 타입을 수용하게 하는 방법은 any 타입을 사용하는 것이지만, any 타입을 사용하게 되면 함수가 리턴할 때 그 타입이 어떤 것인지 정보를 모르게 된다.
따라서, Type 변수를 사용해보자.
function identity<T>(arg: T): T { // Type 변수 T 추가
  return arg;
}
T는 사용자가 제공한 타입을 Capture하여 가지고 있다가 나중에 해당 정보를 사용할 수 있도록 해준다. 그리고 리턴 타입으로 사용하고 있다.
Generic 함수 호출 방법
  1. Type 파라미터를 포함한 모든 파라미터를 함수에 전달하는 방법
let output = identity<string>("myString"); // return type: string
  1. 컴파일러가 전달하는 파라미터의 타입에 따라 자동으로 T의 값을 설정하는 방법(가장 일반적)
let output = identity("myString"); // type: string
// 컴파일러는 "myString"이라는 값을 보고 타입이 string이라고 설정하는 것
// 복잡한 코드에서는 컴파일러가 타입을 추론하지 못할 수도 있으니 타입을 명시적으로 전달해야 할 수도 있다.

Working with Generic Type Variables

function identity<T>(arg: T): T {
  console.log(arg.length) // Error: arg는 length가 없다.
  return arg;
}
위의 경우에는 .length를 사용하고 싶지만 사용할 수 없다. 배열로 받고 싶을 때에는 아래의 경우처럼 사용하면 된다.
function logginIdentity<T>(arg: T[]): T[] {
  console.log(arg.length); // Ok: 사용 가능
  return arg;
}
또는
function logginIdentify<T>(arg: Array<T>): Array<T> {
  console.log(arg.length);
  return arg;
}

Generic Classes

Generic 클래스는 클래스 이름 다음에 꺽쇠 괄호, Generic Type 파라미터 목록을 갖는다.
class GenericNumber<T> {
  zeroValue: T;
  add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

Generic Constraint

맨 처음 예제에서 arg.length를 콘솔에 출력해보면 에러가 났다. .length를 사용하고 싶어서 Generic Type을 항상 <arg: T[]>이런 식으로 하면 안된다. 따라서 모든 타입으로 작업하는 대신, .length를 가진 모든 타입과 함께 동작하도록 제한하고 싶을 경우, 아래와 같이 작성하면 된다.
interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

loggingIdentity(3); // Error: number는 .length 프로퍼티를 가지고 있지 않다.

loggingIdentify({length: 10, value: 3}); // 대신 필수 프로퍼티가 있는 타입 값을 전달해주어야 한다.

Using Type Parameters in Generic Constraints

이름이 있는 객체로부터 프로퍼티를 얻고 싶을 수 있다. 따라서 obj에 존재하지 않는 프로퍼티를 갖지 않도록 제약 조건을 적용할 수 있다.
function getProperty(<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

let x = {a: 1, b: 2, c: 3, d: 4};

getProperty(x, "a"); // Ok
getProperty(x, "m"); // Error: m이라는 프로퍼티는 x 변수에는 없다.

그 외 참고

javascript.info

댓글

가장 많이 본 글