2024-05-15.md
π‘DIL: μ΄νν°λΈ νμ μ€ν¬λ¦½νΈ
μ€ν°λ: μκ° CS, https://github.com/monthly-cs/2024-05-effective-typescript
μμ±μΌ: 2024-05-15
μμ±μ: dusunax
μμ΄ν 7: νμ μ΄ κ°λ€μ μ§ν©μ΄λΌκ³ μκ°νκΈ° Think of Types as Sets of Values
- λ°νμμ λͺ¨λ λ³μλ κ³ μ ν κ°μ κ°μ§
- tsκ° μ€λ₯ 체ν¬λ₯Ό νλ μκ°μλ => κ°μ΄ μλ νμ
μ κ°μ§κ³ μμ
- μ¦, νμ = ν λΉ κ°λ₯ν κ°λ€μ μ§ν© sets of values
- μ΄ μ§ν©μ? νμ μ λ²μ
μ§ν© set
- number νμ μ Number νΉμ strictNullCheck μ€μ μ λ°λΌ null, undefinedμ ν¬ν¨νλ€
- κ°μ₯ μμ μ§ν©μ never. μ무 κ°λ ν¬ν¨νμ§ μλλ€ (곡μ§ν©, empty set)
const x: never = 12; // ~ Type 'number' is not assignable to type 'never'.
- ν κ°μ§ κ°λ§ κ°μ§λ unit, literal νμ
type A = "A"; type B = "B"; type Twelve = 12;
- κ° μ§ν©μ΄ λ μ΄μ μ‘°ν©λ union νμ
(ν©μ§ν©, union)
type AB = "A" | "B"; type AB12 = "A" | "B" | 12;
μ§ν©μ κ΄μ μμμ νμ
"ν λΉ κ°λ₯ν", assignable
- ~μ μμ(κ°κ³Ό νμ ) member
- ~μ λΆλΆμ§ν©(νμ κ³Ό νμ ) subset
subset
-
μ§ν© κ΄μ μμ νμ 체컀μ μν μ νλμ μ§ν©μ΄ λ€λ₯Έ μ§ν©μ λΆλΆ μ§ν©μΈμ§ νμΈ
// OK, {"A", "B"} is a subset of {"A", "B"}: const ab: AB = Math.random() < 0.5 ? "A" : "B"; const ab12: AB12 = ab; // OK, {"A", "B"} is a subset of {"A", "B", 12} declare let twelve: AB12; const back: AB = twelve; // ~~~~ Type 'AB12' is not assignable to type 'AB' // Type '12' is not assignable to type 'AB'
-
μ€μ λ€λ£¨κ² λλ νμ μ λλΆλΆ λ²μκ° λ¬΄νλλ€.
interface Identified { id: string; } // μ΄λ€ κ°μ²΄κ° stringμΌλ‘ ν λΉ κ°λ₯ν id μμ±μ κ°μ§κ³ μλ€λ©΄? κ°μ²΄λ Identifiedλ€. (ꡬ쑰μ νμ΄ν) // excess property checkingμ μκ°νλ€λ³΄λ©΄ κ°κ³ΌνκΈ° μ¬μ (Item 11μ λμ¬ κ²)
μ§ν©μ μ°μ°
&
μ°μ°μλ intersection, λ νμ μ κ΅μ§ν©μ κ³μ°νλ€interface Person { name: string; } interface Lifespan { birth: Date; death?: Date; } type PersonSpan = Person & Lifespan; // Personκ³Ό Lifespan μΈν°νμ΄μ€λ 곡ν΅μΌλ‘ κ°μ§λ μμ±μ΄ μλ€ // νμ μ°μ°μλ μΈν°νμ΄μ€μ μμ±μ΄ μλ, κ°μ μ§ν©μ μ μ©λλ€. (νμ μ λ²μμ μ μ©λλ€) // - Personκ³Ό Lifespanμ λ λ€ κ°μ§λ κ°μ intersectionμ μνκ² λλ€ // - μΈ κ°μ§λ³΄λ€ λ λ§μ μμ±μ κ°μ§λ κ°λ PersonSpanμ μνλ€.
|
μ°μ°μλ λ μΈν°νμ΄μ€μ union
Aμ Bμ μ°μ°
type A = { a: number; b: string };
type B = { b: string; c: boolean };
type ABInteraction = A & B;
type KeysOfABInteraction = keyof ABInteraction; // "a" | "b" | "c"
type ABUnion = A | B;
type KeysOfAUnion = keyof ABUnion; // "b"
// μ§ν©κ³Ό νμ
μ°μ°
keyof (A | B) = (keyof A) & (keyof B)
// κ΅μ§ν©μ λν keyof
// Aμ Bμ κ³΅ν΅ ν€λ§μ ν¬ν¨νλ μΈν°μΉμ
νμ
keyof (A & B) = (keyof A) | (keyof B)
// ν©μ§ν©μ λν keyof
// Aμ Bμ λͺ¨λ ν€λ₯Ό ν¬ν¨νλ μ λμΈ νμ
extends
interface Vector1D {
x: number;
}
interface Vector2D extends Vector1D {
// Vector1Dμ μλΈ νμ
μ΄λ€
y: number;
}
interface Vector3D extends Vector2D {
// Vector2Dμ μλΈ νμ
μ΄λ€
z: number;
}
- νμ μ μ§ν©μ΄λΌλ κ΄μ μμ extendsμ μλ―Έλ assignable(~μ ν λΉ κ°λ₯ν)κ³Ό λΉμ·νκ² subset(~μ λΆλΆ μ§ν©)μ΄λΌλ μλ―Έλ‘ λ°μλ€μΌ μ μλ€.
- subtype μλΈνμ
- μ΄λ€ μ§ν©(set)μ΄ λ€λ₯Έ μ§ν©(set)μ λΆλΆ μ§ν©(subset)μ΄λΌλ λ»
- ν΄λμ€ κ΄μ μμλ μλΈν΄λμ€λ€.
- μ§ν©μ κ΄μ μμλ, μμ κ΄κ³κ° μλλΌ, λ²€ λ€μ΄μ΄κ·Έλ¨μΌλ‘ 그리λ κ²μ΄ μ μ
μ§ν©κ³Ό μ λ€λ¦ νμ , set & generic
- μ λ€λ¦ νμ μμ νμ μλ‘λ μ°μΈλ€. (~μ subset)
function getKey<K extends string>(val: any, key: K) {
// κ°μ²΄ μμμ κ΄μ μ΄λΌλ©΄? κ°μ²΄ Wrapper νμ
Stringμ μλΈν΄λμ€λ₯Ό μ μνλ κ²μ΄μ§λ§...
// μ§ν©μ κ΄μ μμ μκ°νλ€λ©΄? stringμ λΆλΆ μ§ν© λ²μλ₯Ό κ°μ§λ νμ
μ΄ λλ€. K & string
// ...
}
- ν λΉκ³Ό μμ => κ°μ²΄μ ν€ νμ μ λ°ννλ keyof T
function sortBy<K extends keyof T, T>(vals: T[], key: K): T[] {
// ...
}
-
νμ μ΄ μ격ν μμ κ΄κ³κ° μλ λλ μ§ν© μ€νμΌμ΄ λ°λμ§νλ€
-
λ°°μ΄κ³Ό ννμ κ΄κ³
- μ«μ λ°°μ΄μ μ«μμ μμ μλ
- number[]λ₯Ό [number, number]μ ν λΉν μ μμ
- [number, number]λ₯Ό number[]μ ν λΉν μ μμ
const list = [1, 2];
// ^? const list: number[]
const tuple: [number, number] = list;
// ~~~~~ Type 'number[]' is not assignable to type '[number, number]'
// Target requires 2 element(s) but source may have fewer
- νμ μ΄ κ°μ μ§ν©μ΄λΌλ 건? λμΌν κ°μ μ§ν©μ κ°μ§λ λ νμ μ κ°λ€
- μλ―Έμ μΌλ‘ λ€λ₯΄κ³ , μ°μ°ν κ°μ λ²μλλΌλ κ°μ νμ μ λ λ² μ μν νμλ μλ€
Things to Remember
- Think of types as sets of values (the type's domain). These sets can either be finite (e.g., boolean or literal types) or infinite (e.g., number or string).
- νμ μ κ°μ μ§ν©μΌλ‘ μ΄ν΄νκΈ°. (νμ μ λ²μ)
- μ§ν©μ μ ννκ±°λ, 무ννλ€
- TypeScript types form intersecting sets (a Venn diagram) rather than a strict hierarchy. Two types can overlap without either being a subtype of the other.
- νμ μ€ν¬λ¦½νΈ νμ μ μ격ν μμ κ΄κ³κ° μλλΌ, κ²Ήμ³μ§λ μ§ν©μΌλ‘ ννλλ€.
- λ νμ μ μλΈνμ μ΄ μλλ©΄μλ κ²Ήμ³μ§ μ μλ€
- Remember that an object can still belong to a type even if it has additional properties that were not mentioned in the type declaration.
- κ°μ²΄μ νμ μ μΈμ μ‘΄μ¬νμ§ μλ μΆκ° μμ±μ΄ μλλΌλ, κ·Έ νμ μ μν μ μλ€
- Type operations apply to a set's domain. The domain of A | B is the union of the domains of A and B.
- νμ
μ°μ°μ μ§ν©μ λ²μμ μ μ©λλ€.
- A or Bλ Aλ²μμ Bλ²μμ ν©μ§ν©μ΄λ€.
- A and Bλ Aλ²μμ΄κ±°λ, Bλ²μμ΄λ€.
- νμ
μ°μ°μ μ§ν©μ λ²μμ μ μ©λλ€.
- Think of "extends," "assignable to," and "subtype of" as synonyms for "subset of."
- μμ, ν λΉκ°λ₯, μλΈνμ μ μν¨ == λΆλΆ μ§ν©μ μν¨