Skip to main content

Що робить Extract<T, U>?

Що робить Extract<T, U>?

Вибирає з T тільки ті підтипи, які сумісні (assignable) з U. Реалізація в lib.d.ts еквівалентна:

javascript
type Extract<T, U> = T extends U ? T : never;

Приклади:

javascript
type A = Extract<string | number | boolean, number | boolean>; // number | boolean type B = Extract<"a" | "b" | 1, string>; // "a" | "b" type C = Extract<{a:1} | {b:2}, {a:1} | {c:3}>; // {a:1} type D = Extract<"get" | "set" | "reset", `get${string}`>; // "get" type E = Extract<null | undefined | 0, null | undefined>; // null | undefined

Чим Extract протилежний до Exclude?

Exclude<T, U> робить зворотне: прибирає з T все, що сумісне з U.

javascript
type Exclude<T, U> = T extends U ? never : T;

Співвідношення:

  • Extract<T, U> | Exclude<T, U> === T (декомпозиція множини)
  • Extract<T, U> & Exclude<T, U> === never (вони не перетинаються)
  • Тотожність: Extract<T, U> === Exclude<T, Exclude<T, U>>

Міні-приклад:

javascript
type T = string | number | boolean; type OnlyStrings = Extract<T, string>; // string type NotStrings = Exclude<T, string>; // number | boolean

Як Extract працює з union-типами?

Дистрибутивно по T: кожен член об'єднання з T перевіряється на сумісність з U; ті, що проходять, - об'єднуються, ті, що ні - відкидаються.

javascript
type R1 = Extract<"a" | 1 | true, string | number>; // "a" | 1 type R2 = Extract<{x:1} | {y:2}, {x:1}>; // {x:1} type R3 = Extract<never, string>; // never

Тонкощі:

  • З any:
    • Extract<T, any> -> завжди T.
    • Extract<any, U> -> any (через особливі правила умовних типів з any).
  • З unknown:
    • Extract<T, unknown> -> T (все сумісне з unknown).
    • Extract<unknown, U> -> never (окрім випадків, коли unknown явно сумісний з U, що зазвичай не так).
  • З never: завжди never.

Практичні кейси:

javascript
// Дістаємо ключі-рядки зі змішаного union type Keys = Extract<keyof any, string>; // string | number | symbol ∩ string = string // Фільтруємо union за форматом рядка: type HttpGet = Extract<"GET" | "POST" | "PUT", "GET" | "HEAD">; // "GET" // Вибираємо лише функції: type Fn = Extract<string | (() => void) | { run(): void }, Function>; // () => void

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.