타입스크립트 유틸리티 기능 만들어보기
포스트
취소

타입스크립트 유틸리티 기능 만들어보기

해당 포스트는 TypeScriptUtilityTypes을 직접 만들어서 기록하는 게시글입니다.

이펙티브 타입스크립트를 읽으면서 유틸리티 타입이 나오는 경우 답을 보지 않고 먼저 만들고 비교해보는 방식으로 작성합니다.
아마도 이 책에서 언급을 한다면 여태까지 알려줬던 개념들을 활용하면 이해할 수 있다고 판단해서 알려준다고 생각해서 이해를 했다면 구현도 할 수 있을거니까 직접 구현해보는 방식으로 작성하고 있습니다.

📌 Pick<T, K>

이펙티브 타입스크립트 79p

특정 객체 타입과 키들을 받아서 해당 키들만 있는 객체 타입으로 리턴하는 유틸리티 타입입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * + 송신
 * 원본 타입
 * 원본 타입의 key들
 *
 * + 수신
 * 원본 타입에서 해당하는 key들의 집합체
 */
type MyPick<T, K extends keyof T> = {
  [key in K]: T[key];
};

type Person = {
  name: string;
  age: number;
  gender: boolean;
};

type MyPerson = MyPick<Person, "name" | "age">;

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

📌 Partial<T>

이펙티브 타입스크립트 80p

특정 타입을 받아서 모두 옵셔널로 바꾸는 유틸리티 타입입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
 * + 송신
 * 타입
 *
 * + 수신
 * 모두 옵셔널로 변경된 타입
 */
type MyPartial<T> = {
  [key in keyof T]?: T[key];
};

type Person = {
  name: string;
  age: number;
  gender: boolean;
};

type MyPerson = MyPartial<Person>;

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

📌 ReturnType TODO:

이펙티브 타입스크립트 82p

1
2
3
4
5
6
7
8
9
10
11
12
/**
 * + 송신
 * 함수 형태의 타입
 *
 * + 수신
 * 함수의 리턴 값의 타입
 */
type MyReturnType<T> = {};

type Func = (x: number, y: number) => string;

const func: Func = (x, y) => x + y + "";

📌 Record<T, K>

이펙티브 타입스크립트 88p

특정 키들과 값의 타입을 받아서 객체의 타입을 리턴하는 유틸리티 타입입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * + 송신
 * 1. 키들
 * 2. 키들이 가질 타입
 *
 * + 수신
 * 키와 타입을 갖는 객체
 */
type MyRecord<T extends string | number | symbol, K> = {
  [key in T]: K;
};

type Pos = MyRecord<"x" | "y" | "z", number>;

const pos: Pos = { x: 1, y: 1, z: 1 };

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

📌 Readonly<T>

이펙티브 타입스크립트 100p

특정 객체를 받아서 readonly를 적용한채로 반환하는 유틸리티 타입입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
 * + 송신
 * 1. 특정 객체
 *
 * + 수신
 * readonly가 적용된 객체
 */
type MyReadonly<T> = {
  readonly [key in keyof T]: T[key];
};

type Person = {
  name: string;
  age: number;
  vision: {
    left: number;
    right: number;
  };
};

const person: MyReadonly<Person> = {
  name: "alice",
  age: 26,
  vision: {
    left: 1.0,
    right: 1.2,
  },
};

// 불가능
person.name = "blue";

// 가능
person.vision.left = 1.5;

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

📌 Exclude<T, U>

아래 코드가 이해가지 않는다면 조건부 타입를 읽어보시는 것을 추천드립니다!
( 교재에서 언급하진 않았지만 Omit<T, K>를 구현하기 위해 작성했습니다. )

T타입에서 U타입에 포함되는 것을 제외하는 유틸리티 타입입니다.

1
2
3
4
5
6
7
type MyExclude<T, U> = T extends U ? never : T;

type MyType1 = Exclude<"a" | "b" | "c" | "d", "a" | "b">; // "c" | "d"
type MyType2 = MyExclude<"a" | "b" | "c" | "d", "a" | "b">; // "c" | "d"

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

📌 Omit<T, K>

이펙티브 타입스크립트 165p

T타입에서 K라는 key를 갖는 property를 제외하는 유틸리티 타입입니다.
( 대부분 답 보고 풀었습니다… 😢 )

조금 궁금한게 굳이 K extends keyof any를 할 필요가 있는지 궁금하긴 합니다.
추측으로는 어떤 타입이든 상관없이 받으려고 그런 것 같은데 이렇게 만들면 자동완성을 도와주지 않아서 불편하네요..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
type MyPick<T, K extends keyof T> = { [key in K]: T[key] };
type MyExclude<T, U> = T extends U ? never : T;

type MyOmit<T, K extends keyof T> = MyPick<T, MyExclude<keyof T, K>>;

type Champion = {
  name: string;
  speed: number;
  line: "TOP" | "JUG" | "MID" | "AD" | "SUP";
};

type MyType1 = Omit<Champion, "name">;
type MyType2 = MyOmit<Champion, "name">;
/**
 * {
 *   speed: number;
 *   line: "TOP" | "JUG" | "MID" | "AD" | "SUP";
 * }
 */

// ===== 정답 =====
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

📮 레퍼런스

  1. 1-blue - 조건부 타입
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

코어 자바스크립트 3장 ( this )

자바스크립트 완벽 가이드 6장 정리