Capítulo 17 de 36
This page is the original (pre-handbook-v2) treatment of narrowing, mapped types, and conditional types — the TypeScript docs mark it superseded by the newer handbook chapters already covered in this skill (Narrowing, Mapped Types, Conditional Types, Classes), but it's still linked from a lot of older material and contains a few practical angles worth knowing about directly.
in/typeof/instanceof narrowing (see Narrowing), mapped types like Partial/Readonly/Pick/Record (see Mapped Types and Utility Types), conditional types and infer (see Conditional Types), and polymorphic this (see Classes — Advanced). Prefer those chapters for the mechanics; this one adds a handful of things not spelled out elsewhere.strictNullChecks, null/undefined are assignable to every type — TypeScript's opt-in fix for what its own docs call, quoting null's inventor Tony Hoare, the "billion dollar mistake." With it on, string | null and string | undefined are genuinely distinct types, and an optional parameter/property implicitly adds | undefined to its declared type.keyof/indexed-access being their own dedicated chapters): function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] — the canonical example of combining keyof (index type query) and T[K] (indexed access) inside a generic to type-check a dynamic-property-name JS pattern (Object.keys-style extraction) instead of leaving it as any.keyof on index-signature types: a string-indexed type's keyof is string | number (not just string), because JS coerces numeric property access to string lookups under the hood; a purely number-indexed type's keyof is just number.Partial<T>/Readonly<T>/Pick<T, K> are homomorphic — they map only over T's own properties and preserve/copy each property's existing modifiers (readonly, ?) as a side effect of the transform. Record<K, T> is not homomorphic — it doesn't take an input type to copy modifiers from, it manufactures brand-new properties from a key union, so there are no source modifiers to preserve.type Diff<T, U> = T extends U ? never : T / type Filter<T, U> = T extends U ? T : never — the standard pre-built-in-utility-types way to subtract or intersect union members, relying on distribution over a union type parameter (see Conditional Types chapter for the mechanics).type ElementType<T> = T extends any[] ? ElementType<T[number]> : T is an error) — a constraint the newer handbook material doesn't call out explicitly.infer variance: multiple infer sites for the same type variable in co-variant positions (e.g. two return-like positions) infer a union of the candidates; in contra-variant positions (e.g. two function-parameter positions) they infer an intersection instead.function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
return names.map((n) => o[n]);
}
interface Car { manufacturer: string; model: string; year: number }
const taxi: Car = { manufacturer: "Toyota", model: "Camry", year: 2014 };
pluck(taxi, ["manufacturer", "model"]); // string[]
pluck(taxi, ["year", "unknown"]); // Error: "unknown" isn't a key of Car
K extends keyof T type-checking a dynamic property-list extraction — the property names array itself is validated against the object's actual keys.type Foo<T> = T extends { a: infer U; b: infer U } ? U : never;
type Union = Foo<{ a: string; b: number }>; // string | number (co-variant → union)
type Bar<T> = T extends { a: (x: infer U) => void; b: (x: infer U) => void } ? U : never;
type Intersected = Bar<{ a: (x: string) => void; b: (x: number) => void }>; // string & number (contra-variant → intersection)
infer-twice pattern producing a union in a return-like (co-variant) position vs. an intersection in a parameter (contra-variant) position.Pick/Partial/Readonly preserve source modifiers automatically; Record and other property-manufacturing mapped types don't have modifiers to preserve.infer sites for one variable resolve differently depending on variance — union in covariant (output-like) positions, intersection in contravariant (input-like) positions. This is easy to get backwards; verify with a concrete example when it matters.this / fluent-API pattern, covered in full there.