Typescript 유틸리티 클래스 파헤치기

Utility Types Docs를 중점으로

Harry The Great
해리의 유목코딩
7 min readJan 2, 2020

--

Typescript에서 타입에 대한 유틸리티 클래스를 정리한 내용으로 라이브러리 코드에 대한 설명도 포함하고 있기 때문에 간단히 어떤 역할을 하는지와 예시만 보아도 무방합니다. this타입과 관련한 유틸리티 클래스는 apply를 통한 재정의이기 때문에 생략하였습니다.

들어가기에 앞서

유니온(Union)타입

유니온 타입은 하나의 프로퍼티에 다양한 변수가 올 수 있는 타입을 말합니다.

let args: number|string

위에서 변수 args는 숫자 값으로도 할당할 수 있고 문자열로도 할당할 수 있습니다.

let arg: "a" | "b" | "c"

또한 enum값도 union타입으로 표현할 수 있습니다. args 변수는 문자열 a, b, c값만을 할당할 수 있습니다.

keyof 키워드

keyof 키워드는 타입 값에 존재하는 모든 프로퍼티의 키값을 union 형태로 리턴 받습니다.

never 타입

never는 에러가 발생했을 때 프로세스를 중단시키지 않고 무시하는 타입입니다. any를 제외한 다른 모든 타입의 원시 타입으로 사용 가능합니다. 타입이기는 하지만 실제 never 타입으로 변수를 선언할 수 없고 주로 함수의 리턴 타입으로 에러가 발생할 경우 에러를 무시하고 계속 진행시키는 역할을 합니다.

Partial<T>

타입 T의 모든 프로퍼티를 Optional 형태로 바꾸어줍니다.


type Partial
<T> = { [P in keyof T]?: T[P]; };

오른쪽에서 P in keyof T는 타입 T의 프로퍼티 키값에 해당하는 P를 전부 옵셔널(물음표 키워드) 형태로 감싸 리턴합니다.

예시1

Partial은 타입은 원시 타입에 해당하는 프토 퍼티 값을 할당할 수도 안 할 수도 있지만 원시 타입에 존재하지 않는 값은 할당할 수 없습니다.

예시2

위와 같이 destructing을 이용하여 원하는 필드만 값을 변경할 수 있습니다.

Require<T>

모든 Optional 타입들을 언랩핑합니다.

type Required<T> = {
[P in keyof T]-?: T[P];
};

마이너스 연산자는 옵셔널을 제거해주는 연산자입니다.

partials에서 물음표 연산자만 사용한 것처럼 플러스 연산자를 생략할 수 있습니다.

예시

Readonly<T>

모든 프로퍼티를 값을 참조만 할 수 있도록 바꿉니다.

type Readonly<T> = { readonly [P in keyof T]: T[P];};

Partial과 비슷하지만 옵셔널(=?)이 아닌 readonly 키워드를 사용합니다.

예시

Record<K,T>

K타입을 Key값 타입으로, T타입을 밸류 값 타입으로 갖는 타입을 리턴합니다.

type Record<K extends keyof any, T> = {
[P in K]: T;
};

타입 K와 T를 받아 타입 K를 프로퍼티 키값으로 하는 타입을 만들 수 있습니다. 주로 K에 유니온 문자열 값을 주어 map 형식의 타입을 만들 수 있고 여러 값들을 원하는 키값에 따라 분류할 때 유용합니다.

예시

위 예제에서는 SONATA, AVANTE 두 개만을 키값만을 Union string으로 갖는 경우와 string 타입을 키값으로 갖는 경우 두 가지입니다.

응용

만약 Union Type이 아닌 배열의 값을 키값으로 사용하고 싶다면 위처럼 변형하여 사용할 수 있습니다.

Pick<T,K>

T 타입으로부터 K 프로퍼티만 추출합니다.

type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};

키값 T에 속하는 유니온 타입 K를 받아(= K extends keyof T) 매칭 되는 프로퍼티만 리턴합니다.( = [P in K: T [P])

예시

Exclude<T,U>

T 타입들중 U타입들과 겹치는 타입을 제외합니다.

type Exclude<T, U> = T extends U ? never : T;

타입 T가 타입 U를 상속하거나 동일 타입이라면 무시(never)하고 아닐 경우 타입 값을 리턴합니다. 타입 T 또는 타입 U가 유니온 타입으로 온다면 각각의 교집합이 무시(never)됩니다.

예시

Extract<T,U>

T타입에서 U타입과 겹치는 타입만을 가져옵니다.

type Extract<T, U> = T extends U ? T : never;

Exclude와 거의 비슷하지만 T와 never의 위치만 다르기 때문에 교집합을 리턴합니다.예시

Omit<T,K>

Pick과는 정반대로 T타입으로부터 K프토퍼티를 제거합니다.

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

Pick과 Exclude를 한 곳에 넣어놓고 보면 다소 가독성이 떨어져 이해하기 난감할 수 있는데 아래 코드를 보시면 조금 더 쉽게 이해할 수 있습니다.

예시

NonNullable<T>

T타입에서 null or undefinded을 제외하고 리턴합니다.

type NonNullable<T> = T extends null | undefined ? never : T;

null 혹은 undefined 타입이거나 상속한다면 무시(never) 아니라면 타입을 리턴합니다.

예시

Parameters<T>

함수의 파라미터를 타입으로 리턴합니다.

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

T는 (…args: any) => any로 선언되어있습니다. 모든 파라미터를 인자로 받고 결괏값으로 모든 값을 리턴하기 때문에 사실상 모든 함수를 상속합니다.

infer 키워드는 타입 스크립트가 엔진이 런타임 상황에서 타입을 추론할 수 있도록 하고 그 값을 P에 할당해줍니다. 파라미터 타입을 infer P로 할당하고 함수의 형태가 참이라면 파라미터를 아니라면 무시(never)합니다.

예시

any와 never 모두 함수를 대신하여 파라미터 타입으로 사용할 수 있기 때문에 에러가 발생하지 않습니다.

ConstructorParameters<T>

생성자를 갖는 함수 타입의 생성자 파라미터를 리턴합니다. 함수가 아니라면 never를 리턴합니다.

type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;

위의 parameters와 비슷하지만 new키워드를 추가하여 생성자 파라미터로 한정하였습니다.

예시

ReturnType<T>

함수의 리턴타입을 가져옵니다.

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

parameter와 비슷하지만 타입 추론(infer)을 함수의 결괏값에 할당한 후 리턴합니다.

예시

InstanceType<T>

생성자로 초기화된 인스턴스 타입을 리턴합니다.

type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;

타입 추론(infer)을 인스턴스 값에 할당한 후 리턴하였습니다.

예시

빌트인 이외의 리소스

만약 원하는 빌트인 유틸리티 클래스에서 필요한 타입을 찾을 수 없다면 utility-types 를 추천드립니다.

참조

--

--

Harry The Great
해리의 유목코딩

Android & IOS Developer 😀 미디움 이외에 스니펫이나 디버그노트로 활용하는 https://www.harrymikoshi.com/ 블로그도 운영하고있습니다.