InflearnTS Chapter 28~32 - YDP-SPLOUNGE-CLUB/typescript-study GitHub Wiki

Required, Record, NotNullable

๋งŒ์•ฝ ๋ฐ‘์— ์žˆ๋Š” Profile ๊ฐ™์ด ๋ชจ๋“  ์†์„ฑ์ด ์˜ต์…”๋„์ธ ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ๋ชจ๋“  ์†์„ฑ์„ ํ•„์ˆ˜๋กœ ๋ฐ”๊พธ๊ธฐ ์œ„ํ•ด์„œ๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?

interface Profile {
  name?: string,
  age?: number,
  married?: boolean,
}

const zeroCho: Required<Profile> = {
  name: 'zero',
  age: 29,
  married: false,
}

// ์ง์ ‘ Requried ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž.

type R<T> = {
  [Key in keyof T]-?: T[Key];
}

const zeroCho2: R<Profile> = {
  name: 'zero',
  age: 29,
  married: false,
}

Readonly ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ชจ๋“  ์†์„ฑ์— readonly ๋ฅผ ๋ถ™์—ฌ์„œ ๋งŒ๋“ค๊ฑฐ๋‚˜ Readonly ์— - ๋ฅผ ๋ถ™์—ฌ ์—†์•จ ์ˆ˜ ์žˆ๋‹ค.

interface Profile {
  name?: string,
  age?: number,
  married?: boolean,
}

type R<T> = {
  -readonly [Key in keyof T]: T[Key];
}

Record ๋Š” ๋ฐ‘์˜ ์ฝ”๋“œ๋ฅผ ๊ฐ„๋‹จํžˆ ๋ฐ”๊พผ ์ฝ”๋“œ์ด๋‹ค.

interface Obj {
  [key: string]: number;
};

// ๋™์ผ
const a: Record<string, number> = {a: 3}

// Record ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด์ž.

type R<T extends keyof any, S> = {
  [Key in T]: S;
}

NonNullable ์€ Null ์ด๋‚˜ undefined ๋ฅผ ์ œ์™ธํ•˜๊ณ  ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

type A = string | null | undefined | boolean | number;
type B = NonNullable<A>; // string boolean number;

// ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด์ž

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

infer

function zip(x: number, y: string, z: boolean): {
  x: number,
  y: string,
  z: boolean
} {
  return { x, y, z }; 
}

// zip ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์—๊ฒŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค.
type Params = Parameters<typeof zip>;

// ๋˜ํ•œ Parmas ๋Š” ๋ฆฌ์ŠคํŠธํ˜•์ด๊ธฐ ๋–„๋ฌธ์— [0] x: number ์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค.
type First = Params[0];

Parameter ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด์ž.

function zip(x: number, y: string, z: boolean): {
  x: number,
  y: string,
  z: boolean
} {
  return { x, y, z }; 
}

// infer ๋ž€ ์ถ”๋ก ์ด๋ž€ ๋œป์ด๋‹ค.

// Paramemter ๋ฅผ ์˜๋ฏธํ•˜๋Š” P ํ•จ์ˆ˜๋Š” infer A [parameter] ๋ฅผ ์ถ”๋ก ํ•œ๋‹ค.
type P<T extends (...args: any) => any> = T extends (...args: infer A) => any ? A : never;

// ReturnType ๋ฅผ ์˜๋ฏธํ•˜๋Š” R ํ•จ์ˆ˜๋Š” infer A [returns ์ถœ๋ ฅ๊ฐ’] ๋ฅผ ์ถ”๋ก ํ•œ๋‹ค.
type R<T extends (...args: any) => any> = T extends (...args: any) => infer A ? A : never;

type Params = P<typeof zip>;
// ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
// [x: number, y: string, z: boolean]
type Returns = R<typeof zip>;
// ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
// type Returns = {
//   x: number;
//   y: string;
//   z: boolean;
// }

๋˜ ๋‹ค๋ฅธ ์˜ˆ

class A {
  a: string;
  b: number;
  c: boolean;

  constructor(a: string, b: number, c: boolean) {
    this.a = a;
    this.b = b;
    this.c = c;
  }
}

const c = new A('123', 345, true);

// ConstructorParameter ๋ฅผ infer ๋กœ ์ถ”๋ก ํ•˜์—ฌ ๊ฐ€์ ธ์˜จ๋‹ค.
type C = ConstructorParameters<typeof A>;
// ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. [a: string, b: number, c: boolean]

// Instance ์ž์ฒด๋ฅผ ์ถ”๋ก ํ•ด์„œ ๊ฐ€์ ธ์˜จ๋‹ค.
type I = InstanceType<typeof A>;
// ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. A


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

type I2<T extends abstract new (...args :any) => any> =
  T extends abstract new (...args: any) => infer I ? I : never;

infer ์‹ฌํ™”

๋” ์–ด๋ ค์šด ์˜ˆ์ œ๋ฅผ ์ฐพ์•„์™”๋‹ค..

const p1 = Promise.resolve(1).then((a) => a + 1).then((a) => a + 1).then((a) => a.toString());
const p2 = Promise.resolve(2);
const p3 = new Promise((res, rej) => {
  setTimeout(res, 1000);
});

Promise.all([p1, p2, p3]).then((result) => {
  console.log(result); // ํƒ€์ž… ์ถ”๋ก  [string, number, unknown]
});

all ์— ๋Œ€ํ•œ ํƒ€์ž…์„ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

all<T extends readonly unknown[] | []>(values: T): Promise<{-readonly [P in keyof T]: Awaited<T[P]>}>;

ํ•ด์„ ์ˆœ์„œ

  1. Promise.all ์•ˆ์— ์žˆ๋Š” ๊ฐ์ฒด๋“ค์„ readonly ๋กœ ์ฝ์–ด๋“ค์ธ๋‹ค.
  2. Promise ํ•ด์„์ด ๋๋‚œ ์ƒํƒœ์—์„œ๋Š” readonly ๋ฅผ ์‚ญ์ œ์‹œ์ผœ ์ž์œ ๋กœ์šด ์ƒํƒœ๋กœ ๋ณ€ํ™˜์‹œ์ผœ ์ค€๋‹ค.
  3. Awaited ๋ผ๋Š” ํƒ€์ž… ๋‚ด์—์„œ then ์˜ ๊ฐ’์„ Return ์‹œ์ผœ์ค€๋‹ค.

Awaited ๋ผ๋Š” ํ•จ์ˆ˜์—์„œ ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚ฌ๋Š”๊ฐ€?

type Awaited<T> =
  T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode
    T extends object & { then(onfulfilled: infer F): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped
      F extends ((value: infer V, ...args: any) => any) ? // if the argument to `then` is callable, extracts the first argument
        Awaited<V> : // recursively unwrap the value
        never : // the argument to `then` was not callable
      T; // non-object or non-thenable

p1 ์„ ์˜ˆ์‹œ๋กœ ์ˆœ์ฐจ์ ์œผ๋กœ ํ•ด์„ํ•ด๋ณด๋ฉด

  1. T๊ฐ€ null ๋˜๋Š” undefined ์ธ๊ฐ€? false ์ด๋ฏ€๋กœ T ๊ฐ’์„ ๋‚ด๋ณด๋‚ด์ง€ ์•Š๊ณ  ๋‹ค์Œ ํƒ€์ž…์„ ํ•ด์„ํ•œ๋‹ค.
  2. T extends object & { then(onfulfilled: infer F): any } <- ๋•ํƒ€์ดํ•‘ ์„ ํ†ตํ•ด์„œ then ์ด ์žˆ๋Š” ํ•จ์ˆ˜์ธ์ง€๋ฅผ ํŒ๋ณ„
  3. F ๊ฐ€ true ๋ผ๋ฉด Awaited ๋ฅผ ํ†ตํ•ด์„œ ๋‹ค์‹œํ•œ๋ฒˆ ์žฌ๊ท€ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฉฐ
  4. F ๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ extends ๋ฅผ ๋งŒ์กฑ์‹œํ‚ค์ง€ ์•Š๋Š” ํ•จ์ˆ˜๋ผ๋ฉด ํ•จ์ˆ˜์— ์•„๋ฌด๋Ÿฐ ๊ฐ’์„ ๋‚ด๋ณด๋‚ด์ง€ ์•Š๋Š”๋‹ค.
  5. T extends object & { then(onfulfilled: infer F): any } ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด T ๋ฒจ๋ฅ˜ ์ž์ฒด๋ฅผ ๋‚ด๋ณด๋‚ธ๋‹ค.
  6. p1 ์˜ ์ฒซ ๊ฐ’์€ number.then(...) ์ด๋ฏ€๋กœ then(onfulfilled: inter F): any ์— ์ ํ•ฉํ•˜๋ฏ€๋กœ
  7. F extends ((value: infer V, ...args: any) => any) ? (a + 1) ๋ฅผ ์ฝ์–ด๋“ค์ด๋ฉฐ Awaited ์žฌ๊ท€๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
  8. ์žฌ๊ท€๋ฅผ ๋ฐ˜๋ณตํ•˜๋ฉฐ ๋งˆ์ง€๋ง‰ v.toString() ๊นŒ์ง€ ๋„๋‹ฌํ•˜์˜€๊ณ  ๋’ค์— ์ถ”๊ฐ€์ ์œผ๋กœ ๋ถ™๋Š” then ์ด ์—†์œผ๋ฏ€๋กœ T extends object & { then(onfulfilled: infer F): any } ์กฐ๊ฑด์— ๋ถˆ๋งŒ์กฑํ•œ๋‹ค.
  9. T ๋ผ๋Š” ๊ฐ’์„ ๋‚ด๋ณด๋‚ด๋ฉฐ p1 ์˜ resolve ๊ฐ’์€ string ์ด ๋œ๋‹ค.

flat

const a = [1,2,3, [1,2], [[1], [2]]].flat(); // (number| number[])[]
const a2 = [1,2,3, [1,2], [[1], [2]]].flat(2); // number[]

FlatArray ์— ๊ด€ํ•œ ํƒ€์ž…์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

type FlatArray<Arr, Depth extends number> = {
  "done": Arr,
  "recur": Arr extends ReadonlyArray<infer InnerArr>
      ? FlatArray<InnerArr, [-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20][Depth]>
      : Arr
}[Depth extends -1 ? "done": "recur"];

์‰ฝ๊ฒŒ ์„ค๋ช…ํ•˜๋ฉด depth ๊ฐ€ ๋๋‚ฌ๋‹ค๋ฉด done ์„ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐฐ์—ด ๊ทธ๋Œ€๋กœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ ์•„๋‹ˆ๋ผ๋ฉด Arr ์„ Depth ๋ฅผ ํ’€์–ด์ค˜์„œ ์žฌ๊ท€ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

๋งŒ์•ฝ flat(1) ์ด๋ผ๋ฉด -> 0 ์„ ํ˜ธ์ถœํ•˜๊ณ  flat(0) ์„ ํ˜ธ์ถœํ•˜๊ณ  ๊ทธ ์ดํ›„ -1 ์„ ํ˜ธ์ถœํ•˜์—ฌ "done" ์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋œ๋‹ค.

20์ฐจ์›์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ณ ๋ คํ•ด์คฌ์ง€๋งŒ 25์ฐจ์› ์ฏค ๋˜๋ฉด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ดํ•ด๋ฅผ ๋ชปํ•œ๋‹ค.

๋‹ค์‹œ ๋Œ์•„๊ฐ€์„œ

// ํ•ด๋‹น ํ•จ์ˆ˜์—์„œ infer InnerArr ๋Š” ๋ฆฌ์ŠคํŠธ ์•ˆ์ชฝ์— ์žˆ๋Š” ๋ฐฐ์—ด๋“ค์ด๋‹ค.
// infer InnerArr = number, number[], number[][]

const a = [1,2,3, [1,2], [[1], [2]]].flat(2);

์ˆœ์ฐจ์ ์œผ๋กœ ์ •๋ฆฌํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  1. FlatArray<(number[] | number[][] | number[][][]), 2>[] ์ƒํƒœ์—์„œ FlatArray ๋ฅผ ํ˜ธ์ถœ FlatArray Depth ๊ฐ€ 2 ์ด๋ฏ€๋กœ ReadOnlyArray number[] | number[][] | number[][][] ์˜ ์•ˆ์ชฝ ๋ฐฐ์—ด์„ ์ฝ์–ด ํ•œ ์ฐจ์› ๋ฐ‘์œผ๋กœ ๋‚ด๋ฆฐ๋‹ค. ๋˜ํ•œ FlayArray<InnerArray, -1,0,1,2,...[2] = 1 ๋ฅผ ๋ถˆ๋Ÿฌ๋‚ด์„œ ์žฌ๊ท€ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰
  2. FlatArray<(number | number[] | number[][]), 1>[] ๋ฐ˜๋ณต
  3. FlatArray<(number | number[]), 0>[] ๋ฐ˜๋ณต
  4. FlatArray<number, -1>[] -1 ์ด๋ฏ€๋กœ Arr ์ž์ฒด๋ฅผ ๋ฐ˜ํ™˜
  5. number []
โš ๏ธ **GitHub.com Fallback** โš ๏ธ