LearningTS Chapter 15 - YDP-SPLOUNGE-CLUB/typescript-study GitHub Wiki

15.1 λ§€ν•‘λœ νƒ€μž…

νƒ€μž…μŠ€ν¬λ¦½νŠΈλŠ” λ‹€λ₯Έ νƒ€μž…μ˜ 속성λ₯΄ 기반으둜 μƒˆλ‘œμš΄ νƒ€μž…μ„ μƒμ„±ν•˜λŠ” ꡬ문을 μ œκ³΅ν•œλ‹€.

// example
type NewType = {
  [K in OriginalType]: NewProperty;
}

λ§€ν•‘λœνƒ€μž…μ— λŒ€ν•œ 일반적인 μ‚¬μš© μ‚¬λ‘€λŠ” μœ λ‹ˆμ–Έ νƒ€μž…μ„ ν˜Όν•©ν•˜μ—¬ μƒμš©ν•˜μ—¬ 각 λ¬Έμžμ—΄ λ¦¬ν„°λŸ΄ ν‚€λ₯Ό κ°€μ§„ 객체λ₯Ό μƒμ„±ν•˜λŠ” 것이닀.

type Animals = "alligator" | "baboon" | "cat";

type AnimalCounts = {
  [K in Animals]: number;
};

15.1.1 νƒ€μž…μ—μ„œ λ§€ν•‘λœ νƒ€μž…

일반적으둜 λ§€ν•‘λœ νƒ€μž…μ€ μ‘΄μž¬ν•˜λŠ” νƒ€μž…μ— keyof μ—°μ‚°μžλ₯Ό μ‚¬μš©ν•΄ ν‚€λ₯Ό κ°€μ Έμ˜€λŠ” λ°©μ‹μœΌλ‘œ μž‘λ™ν•œλ‹€.

μ‘΄μž¬ν•˜λŠ” νƒ€μž…μ˜ ν‚€λ₯Ό λ§€ν•‘ν•˜λ„λ‘ 탕비에 μ§€μ‹œν•˜λ©΄ μƒˆλ‘œμš΄ νƒ€μž…μœΌλ‘œ λ§€ν•‘λœλ‹€.

interface AnimalVariants {
  aliigator: boolean;
  baboon: number;
  cat: string;
}

type AnimalCounts = {
  [K in keyof AnimalVariants]: number;
}

이전 μŠ€λ‹ˆνŽ«μ—μ„œ K 둜 λͺ…λͺ…λœ keyof 에 λ§€ν•‘λœ μƒˆλ‘œμš΄ νƒ€μž… ν‚€λŠ” μ›λž˜ νƒ€μž…μ˜ ν‚€λ‘œ μ•Œλ €μ Έ μžˆλ‹€. 즉 각 λ§€ν•‘λœ νƒ€μž… 멀버 값은 λ™μΌν•œ ν‚€ μ•„λž˜μ—μ„œ μ›λž˜ νƒ€μž…μ˜ ν•΄λ‹Ή 멀버 값을 μ°Έμ‘°ν•  수 μžˆλ‹€.

원본 객체가 SomeName 이고 맀핑이 [K in keyof SomeName]인 경우라면 λ§€ν•‘λœ νƒ€μž…μ˜ 각 λ©€λ²„λŠ” SomeName 멀버이 값을 SomeName[K] 둜 μ°Έμ‘°ν•  수 μžˆλ‹€.

interface BirdVariants {
  dove: string;
  eagle: boolean;
}

type NullableBirdVarinats = {
  [K in keyof BirdVariants]: BirdVariants[K] | null;
}

λ§€ν•‘λœ νƒ€μž…κ³Ό μ‹œκ·Έλ‹ˆμ³

μΈν„°νŽ˜μ΄μŠ€ 멀버λ₯Ό ν•¨μˆ˜λ‘œ μ„ μ–Έν•˜λŠ” 두 κ°€μ§€ 방법을 μ œμ‹œν–ˆμ—ˆλ‹€.

  • member(): void ꡬ문 : μΈν„°νŽ˜μ΄μŠ€ 멀버가 객체의 λ©€λ²„λ‘œ ν˜ΈμΆœλ˜λ„λ‘ μ˜λ„λœ ν•¨μˆ˜μž„μ„ μ„ μ–Έ
  • member: () => void ꡬ문 : μΈν„°νŽ˜μ΄μŠ€μ˜ 멀버가 독립 μ‹€ν–‰ν˜• ν•¨μˆ˜μ™€ κ°™λ‹€κ³  μ„ μ–Έ

λ§€ν•‘λœ νƒ€μž…μ€ 객체 νƒ€μž…μ˜ λ©”μ„œλ“œμ™€ 속성 ꡬ문을 κ΅¬λΆ„ν•˜μ§€ μ•ŠλŠ”λ‹€. λ§€ν•‘λœ νƒ€μž…μ€ λ©”μ„œλ“œλ₯Ό μ›λž˜ νƒ€μž…μ˜ μ†μ„±μœΌλ‘œ μ·¨κΈ‰

interface Researcher {
  researchMethod(): void;
  researchProperty: () => string;
}

type JustProperties<T> = {
  [K in typeof T]: T[K]
};

type ResearcherProperties = JustProperties<Researcher>;

// λ‹€μŒκ³Ό κ°™λ‹€.
// {
//   researchMethod: () => void;
//   researchProperty: () => string;
// }

15.1.2 μ œν•œμž λ³€κ²½

λ§€ν•‘λœ νƒ€μž…μ€ μ›λž˜ νƒ•λΉ„μ˜ 멀버에 λŒ€ν•΄ μ ‘κ·Ό μ œμ–΄ μ œν•œμžμΈ readonly 와 ? 도 λ³€κ²½ κ°€λŠ₯ν•˜λ‹€.

μ „ν˜•μ μΈ μΈν„°νŽ˜μ΄μŠ€μ™€ λ™μΌν•œ ꡬ문을 μ‚¬μš©ν•΄ λ§€ν•‘λœ νƒ€μž…μ˜ 멀버에 readonly 와 ? λ₯Ό 배치 κ°€λŠ₯ν•˜λ‹€.

interface Enviromentalist{
  area: string;
  name: string;
}

type ReadOnlyEnviromentalist = {
  readonly [K in keyof Enviromentalist]: Enviromentalist[K];
};

// λ‹€μŒκ³Ό κ°™μŒ
// {
//   readonly area: string;
//   readonly name: string;
// }

type OptionalReadOnlyEnviromentalist = {
  [K in keyof ReadOnlyEnviromentalist]?: Enviromentalist[K];
};

μƒˆλ‘œμš΄ νƒ€μž… μ œν•œμž μ•žμ— - λ₯Ό μΆ”κ°€ν•΄ μ œν•œμžλ₯Ό 제거 κ°€λŠ₯ν•˜λ‹€.

interface Conservationist {
  name: string;
  catchphrase?: string;
  readonly born: number;
  readonly died?: number;
}

type WrtableConservationist = {
  -readonly [K in keyof Conservationist]: Conservationist[K];
};

// λ‹€μŒκ³Ό κ°™μŒ.
// {
//   name: string;
//   catchprase?: string;
//   born: number;
//   died?: number;
// }

type RequireWritableConservationist = {
  [K in keyof WrtableConservationist]-?: WrtableConservationist[K];
};

15.1.3 μ œλ„€λ¦­ λ§€ν•‘λœ νƒ€μž…

λ§€ν•‘λœ νƒ€μž…μ˜ μ™„μ „ν•œ νž˜μ€ μ œλ„€λ¦­κ³Ό κ²°ν•©ν•΄ 단일 νƒ€μž…μ˜ 맀핑을 λ‹€λ₯Έ νƒ€μž…μ—μ„œ μž¬μ‚¬μš©ν•  수 μžˆλ„λ‘ ν•˜λŠ” κ²ƒμ—μ„œ λ‚˜μ˜¨λ‹€.

λ§€ν•‘λœ νƒ€μž…μ€ λ§€ν•‘λœ νƒ€μž… 자체의 νƒ€μž… λ§€κ°œλ³€μˆ˜λ₯Ό 포함해 keyof 둜 ν•΄λ‹Ή μŠ€μ½”ν”„μ— μžˆλŠ” λͺ¨λ“  νƒ€μž… 이름에 μ ‘κ·Όν•  수 μžˆλ‹€.

μ œλ„€λ¦­ λ§€ν•‘λœ 탕비은 데이터가 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ 톡해 흐λ₯Ό λ•Œ 데이터가 μ–΄λ–»κ²Œ λ³€ν˜•λ˜λŠ”μ§€ λ‚˜νƒ€λ‚Ό λ•Œ μœ μš©ν•˜λ‹€.

type MakeReadonly<T> = {
  readonly [K in keyof T]: T[K];
}

interface Species {
  genus: string;
  name: string;
}

type ReadonlySpecies = MakeReadonly<Species>;

κ°œλ°œμžλ“€μ΄ 일반적으둜 ν‘œν˜„ν•΄μ•Ό ν•˜λŠ” 또 λ‹€λ₯Έ λ³€ν™˜μ€ μž„μ˜μ˜ 수의 μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ°›κ³  κ·Έ μΈν„°νŽ˜μ΄μŠ€μ˜ μ™„μ „νžˆ μ±„μ›Œμ§„ μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜μ΄λ‹€.

interface GenusData {
  family: string;
  name: string;
}

type MakeOptinal<T> = {
  [K in keyof T]?: T[K];
}

function createGenusData(overrides?: MakeOptinal<GenusData>): GenusData {
  return {
    family: 'unknown',
    name: 'unknown',
    ...overrides,
  }
}

15.2 쑰건뢀 νƒ€μž…

κΈ°μ‘΄ νƒ€μž…μ„ λ‹€λ₯Έ νƒ€μž…μ— λ§€ν•‘ν•˜λŠ” 것은 ν›Œλ₯­ν•˜μ§€λ§Œ 아직 νƒ€μž… μ‹œμŠ€ν…œμ— 논리적 쑰건이 μΆ”κ°€λ˜μ§€ μ•Šμ•˜λ‹€.

νƒ€μž…μŠ€ν¬λ¦½νŠΈμ˜ νƒ€μž… μ‹œμŠ€ν…œμ€ 논리 ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄μ˜ ν•œ μ˜ˆμ΄λ‹€.

νƒ€μž… μ‹œμŠ€ν…œμ€ 이전 νƒ€μž…μ— λŒ€ν•œ 논리적인 검사λ₯Ό λ°”νƒ•μœΌλ‘œ μƒˆλ‘œμš΄ ꡬ성을 μƒμ„±ν•œλ‹€. 쑰건뢀 νƒ€μž…μ˜ κ°œλ…μ€

κΈ°μ‘΄ νƒ€μž…μ„ λ°”νƒ•μœΌλ‘œ 두 κ°€μ§€ κ°€λŠ₯ν•œ νƒ€μž… 쀑 ν•˜λ‚˜λ‘œ ν™•μΈλ˜λŠ” νƒ€μž…μ΄λ‹€.

쑰건뢀 νƒ€μž… ꡬ문은 μ‚Όν•­ μ—°μ‚°μž 쑰건문처럼 보인닀.

LeftType extends RightType ? IfTrue : IfFalse;

쑰건뢀 νƒ€μž…μ—μ„œ 논리적 κ²€μ‚¬λŠ” 항상 extends 의 μ™Όμͺ½ νƒ€μž…μ΄ 였λ₯Έμͺ½ νƒ€μž…μ΄ λ˜λŠ”μ§€ λ˜λŠ” ν• λ‹Ή κ°€λŠ₯ν•œμ§€ 여뢀에 μžˆλ‹€.

λ‹€μŒ CheckStringAgainstNumber 쑰건뢀 νƒ€μž…μ€ string | number κ°€ λ˜λŠ”μ§€ μ—¬λΆ€λ₯Ό κ²€μ‚¬ν•œλ‹€.

string νƒ€μž…μ„ number νƒ€μž…μ— ν• λ‹Ήν•  수 μžˆλŠ”μ§€ 여뢀이닀. ν• λ‹Ήν•  수 μ—†λ‹€λ©΄ κ·Έ κ²°κ³Ό νƒ€μž…μ€ false κ°€ λœλ‹€.

type CheckStringAginstNumber = string extends number ? true : false;

15.2.1 μ œλ„€λ¦­ 쑰건뢀 νƒ€μž…

쑰건뢀 νƒ€μž…μ€ 쑰건뢀 νƒ€μž… 자체의 νƒ€μž… λ§€κ°œλ³€μˆ˜λ₯Ό ν¬ν•¨ν•œ ν•΄λ‹Ή μŠ€μ½”ν”„μ—μ„œ λͺ¨λ“  νƒ€μž… 이름을 확인할 수 μžˆλ‹€.

즉 λͺ¨λ“  λ‹€λ₯Έ νƒ€μž…μ„ 기반으둜 μƒˆλ‘œμš΄ νƒ€μž…μ„ μƒμ„±ν•˜κΈ° μœ„ν•΄ μž¬μ‚¬μš© κ°€λŠ₯ν•œ μ œλ„€λ¦­ νƒ€μž…μ„ μž‘μ„±ν•  수 μžˆλ‹€.

type CheckAgaubstNumber<T> = T extends number ? true : false;

// νƒ€μž… : false
type CheckString = CheckAgaubstNumber<'parakeet'>;

// νƒ€μž… : true
type CheckString = CheckAgaubstNumber<1111>;

// νƒ€μž… : true
type CheckString = CheckAgaubstNumber<number>;
interface QuertOptions {
  thorwIfNotFound: boolean;
}

type QueryResult<Options extends QuertOptions> = 
  Options["thorwIfNotFound"] extends true ? string : string | undefined;

declare function retrieve<Options extends QuertOptions>(
  key: string,
  options?: Options,
): Promise<QueryResult<Options>>;

// λ°˜ν™˜ νƒ€μž… string | undefined;
await retrieve("Mary");

// string | undefined;
await retrieve("Jane", { thorwIfNotFound: Math.random() > 0.5 });

// string
await retrieve("Dian", { thorwIfNotFound: true });

15.2.2 νƒ€μž… λΆ„μ‚°

type ArrayifUnlessString<T> = T extends string ? T: T[];

// string | number[]
type HalfArrayified = ArrayifUnlessString<string | number>;

νƒ€μž…μŠ€ν¬λ¦½νŠΈμ˜ 쑰건뢀 νƒ€μž…μ΄ μœ λ‹ˆμ–Έμ— λΆ„μ‚°λ˜μ§€ μ•ŠλŠ”λ‹€λ©΄ string | number λŠ” string 에 ν• λ‹Ήν•  수 μ—†κΈ° 떄문에 HalfArrayified λŠ” (string | number)[] κ°€ λœλ‹€.

15.2.3 μœ μΈ„λœ νƒ€μž…

제곡된 νƒ€μž…μ˜ 멀버에 μ ‘κ·Όν•˜λŠ” 것은 νƒ€μž…μ˜ λ©€λ²„λ‘œ μ €μž₯된 정보에 λŒ€ν•΄μ„œλŠ” 잘 μž‘λ™ν•˜μ§€λ§Œ ν•¨μˆ˜ λ§€κ°œλ³€μˆ˜ λ˜λŠ” λ°˜ν™˜ νƒ€μž…κ³Ό 같은 λ‹€λ₯Έ 정보에 λŒ€ν•΄μ„œλŠ” μ•Œ 수 μ—†λ‹€.

쑰건뢀 νƒ€μž…μ€ extends μ ˆμ— infer ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄ 쑰건의 μž„μ˜μ˜ 뢀뢄에 μ ‘κ·Όν•œλ‹€.

extends μ ˆμ— νƒ€μž…μ— λŒ€ν•œ infer ν‚€μ›Œλ“œμ™€ μƒˆ 이름을 λ°°μΉ˜ν•˜λ©΄ 쑰건뢀 νƒ€μž…μ΄ true 인 경우 μƒˆλ‘œμš΄ νƒ€μž…μ„ μ‚¬μš©ν•  수 μžˆμŒμ„ μ˜λ―Έν•œλ‹€.

infer μ΄λž€ μ œλ„€λ¦­ νŒŒλΌλ―Έν„°μ— λ“€μ–΄κ°„ νƒ€μž…μ„ 뽑아내 λ‹€λ₯Έ λ³€μˆ˜μ— 넣어두어 νƒ€μž…μ„ μ„ μ–Έν• λ•Œ μ‚¬μš©ν•˜κΈ°λ„ν•œλ‹€.

type ArrayItems<T> = 
  T extends (infer item)[]
    ? item
    : T;

// string
type StringItem = ArrayItems<string>;

// string
type StringArrayItem = ArrayItems<string[]>;

// string[]
type String2DItem = ArrayItems<string[][]>;

νƒ€μž… λ§€κ°œλ³€μˆ˜ Tλ₯Ό λ°›κ³  μƒˆλ‘œμš΄ Item νƒ€μž…μ˜ 배열인지 ν™•μΈν•œλ‹€. μƒˆλ‘œμš΄ Item νƒ€μž…μ˜ 배열인 경우 κ²°κ³Ό νƒ€μž…μ€ Item 이 되고 κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ T κ°€ λœλ‹€.

// infer 와 같은 μœ„μΉ˜μ— μžˆλŠ” string νƒ€μž…μ„ R λ³€μˆ˜μ— μ„ μ–Έν•œλ‹€.
type ArrType<T> = T extends (infer R)[] ? R : unknown;

type arr = ArrType<string[]>;	// string νƒ€μž…μ΄λ‹€.
type arr2 = ArrType<string>;	// unknown νƒ€μž…μ΄λ‹€.

15.2.4 λ§€ν•‘λœ 쑰건뢀 νƒ€μž…

λ§€ν•‘λœ νƒ€μž…μ€ κΈ°μ‘΄ νƒ€μž…μ˜ λͺ¨λ“  멀버에 λ³€κ²½ 사항을 μ μš©ν•˜κ³  쑰건뢀 νƒ€μž…μ€ ν•˜λ‚˜μ˜ κΈ°μ‘΄ νƒ€μž…μ— λ³€κ²½ 사항을 μ μš©ν•œλ‹€.

type MakeAllMembersfunctions<T> = {
  [K in keyof T]: T[K] extends (...args: any[]) => any
      ? T[K]
      : () => T[K]
};

type MemberFunctions = MakeAllMembersfunctions<{
  alreadyFunction: () => string,
  notYetFunction: number;
}>

//
// {
//   alreadyfunction: () => string;
//   notYetFUnction: () => number;
// }

15.4 ν…œν”Œλ¦Ώ λ¦¬ν„°λŸ΄ νƒ€μž…

λ¬Έμžμ—΄κ°’μ„ μž…λ ₯ν•˜κΈ° μœ„ν•œ 두 κ°€μ§€ μ „λž΅μ„ μ œμ‹œν•œ 적이 μžˆλ‹€.

μ›μ‹œ string νƒ€μž… : 값이 μ„Έμƒμ˜ λͺ¨λ“  λ¬Έμžμ—΄μ΄ 될 수 μžˆλŠ” 경우 "" 와 "abc" 같은 λ¦¬ν„°λŸ΄ νƒ€μž…: 값이 였직 ν•œ κ°€μ§€ νƒ€μž…λ§Œ 될 수 μžˆλŠ” 경우

λ¬Έμžμ—΄ νƒ€μž…μ΄ νŒ¨ν„΄μ— λ§žλŠ”μ§€λ₯Ό λ‚˜νƒ€λ‚΄λŠ” νƒ€μž…μŠ€ν¬λ¦½νŠΈ ꡬ문인 ν…œν”Œλ¦Ώ λ¦¬ν„°λŸ΄ νƒ€μž…μ„ μž…λ ₯ν•΄λ³΄μž

type Greeting = `Hello${string}`;

let matches: Greeting = "Hello, world!"; // OK

let outOfOrder: Greeting = "World! Hello"; // Error
type Brightness = "dark" | "light";
type Color = "blue" | "red";

type BrightnessAndColor = `${Brightness}-${Color}`;

let colorOk: BrightnessAndColor = "dark-blue";

15.4.1 고유 λ¬Έμžμ—΄ μ‘°μž‘ νƒ€μž…

λ¬Έμžμ—΄ νƒ€μž… μž‘μ—…μ„ μ§€μ›ν•˜κΈ° μœ„ν•΄ νƒ€μž…μŠ€ν¬λ¦½νŠΈλŠ” λ¬Έμžμ—΄μ„κ°€μ Έμ™€ λ¬Έμžμ—΄μ— 일뢀 μ‘°μž‘μ„ μ μš©ν•˜λŠ” 고유 μ œλ„€λ¦­ μœ ν‹Έλ¦¬ν‹° νƒ€μž…μ„ μ œκ³΅ν•œλ‹€.

  • Uppercase
  • Lowercase
  • Capitalize
  • Uncapitalize
type FormalGreeting = Capitalize<"hello,">; // Hello,
const config = {
  location: 'unknown',
  name: "annoymous",
  year: 0,
}

type LayValues = {
  [K in keyof typeof config as `${K}Lazy`]: () => Promise<typeof config[K]>;
};

async function withLazyValues(configGetter: LayValues) {
  await configGetter.locationLazy; // string
  
  await configGetter.missingLazy; // Error Propery missingLazy does not exist
}

μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ 객체 ν‚€λŠ” string λ˜λŠ” Symbol 이 될 수 있고 Symbol ν‚€λŠ” μ›μ‹œ νƒ€μž…μ΄ μ•„λ‹ˆλ―€λ‘œ ν…œν”Œλ¦Ώ λ¦¬ν„°λŸ΄ νƒ€μž…μœΌλ‘œ μ‚¬μš©ν•  수 μ—†λ‹€.

type TurnIntoGettersDirect<T> = {
  [K in keyof T as `get${K}`]: () => T[K]
  // Error
}

μ΄λŸ¬ν•œ μ œν•œ 사항을 ν”Όν•˜κΈ° μœ„ν•΄ string κ³Ό ꡐ차 νƒ€μž… & 을 μ‚¬μš©ν•˜μ—¬ λ¬Έμžμ—΄μ΄ 될 수 μžˆλŠ” νƒ€μž…λ§Œ μ‚¬μš©ν•˜λ„λ‘ κ°•μ œν•œλ‹€.

string & symbol 은 never κ°€ λ˜λ―€λ‘œ 전체 ν…œν”Œλ¦Ώ λ¬Έμžμ—΄μ€ neverκ°€ λ˜λ―€λ‘œ 전체 ν…œν”Œλ¦Ώ λ¬Έμžμ—΄μ€ never κ°€ 되고 νƒ€μž…μŠ€ν¬λ¦½νŠΈλŠ” 이λ₯Ό λ¬΄μ‹œν•œλ‹€.

const someSymbol = Symbol("");

interface HasStringAndSymbol {
  Stringkey: string;
  [someSymbol]: number;
}

type TurnIntoGetters<T> = {
  [K in keyof T as `get${string & K}`]: () => T[K]
};

type GettersJustString = TurnIntoGetters<HasStringAndSymbol>;

// λ‹€μŒκ³Ό κ°™μŒ.
// {
//   getStringkey: () => string;
// }
⚠️ **GitHub.com Fallback** ⚠️