Suggest an editImprove this articleRefine the answer for “Utility type extract in TypeScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Extract<T, U>** keeps from union T only the members assignable to U. ```ts type Status = "success" | "error" | 200; type StringStatuses = Extract<Status, string>; // "success" | "error" ``` **Key:** Works as `T extends U ? T : never` distributed over each union member. Opposite of `Exclude`.Shown above the full answer for quick recall.Answer (EN)Image**Extract<T, U>** picks from a union type T only the members assignable to U, returning a narrower union of matching types. ## Theory ### TL;DR - Think of a factory conveyor belt: drop in a mixed crate of parts (union T), set the filter shape (U), and only matching parts come out. - `Extract` checks assignability, not exact equality. A member passes if it structurally fits U. - Returns `never` when nothing matches. Account for that in function signatures. - Use it when a union is too broad for a specific branch and you need a type-safe subset. - Opposite of `Exclude<T, U>`. ### Quick example ```ts type Status = "success" | "error" | "pending" | 200; type StringStatuses = Extract<Status, string>; // Result: "success" | "error" | "pending" // 200 is a number, not assignable to string, so it is filtered out const code: StringStatuses = "error"; // OK const num: StringStatuses = 200; // Type error ``` `Extract` walked through each member of `Status` and kept only those assignable to `string`. The number `200` did not pass. ### Key difference `Extract` tests assignability, not exact equality. So `Extract<"success" | "error", string>` returns `"success" | "error"` because both string literals are assignable to `string`. This also works for objects: if a union member has all the properties U requires, plus extras, it still passes through. ### When to use - API response union too wide: extract the error or success subtype for a dedicated handler. - Role-based access: pull admin-level roles from a full roles union. - Discriminated unions: extract variants with a specific discriminant value. - Event filtering: keep only the event types your handler actually covers. ### How the compiler handles this TypeScript expands `Extract<T, U>` as `T extends U ? T : never`, applied to each union member separately. For each constituent, it checks structural assignability. No runtime cost - the type is erased at emit. This behavior is available since TypeScript 2.8, when conditional types were introduced. ### Common mistakes **1. Expecting partial string matching** ```ts type Status = "error" | "ERR_404"; type Want = Extract<Status, "error">; // "error" only. "ERR_404" is not assignable to the literal "error". ``` These are different literal types. Assignability between literals is exact. If you need both, use `Extract<Status, "error" | "ERR_404">`. **2. Nested object mismatch** ```ts type Deep = { a: "x" } | { a: { b: "y" } }; type Fail = Extract<Deep, { a: string }>; // never! { b: "y" } is not assignable to string ``` TypeScript checks the full structure. A nested object is not a string. If you need to drill into a property, use `Extract<Deep["a"], string>`. **3. Ignoring `never` results** ```ts type None = Extract<"a" | "b", number>; // never function handle(x: None) {} // Uncallable - TypeScript errors at every call site ``` When nothing matches, you get `never`. A variable typed as `never` cannot be assigned anything. Check your filter type before using the result in a function signature. ### Real-world usage From production React codebases, `Extract` shows up most often around API response types and role checks. A few concrete spots: - React Query: `Extract<UseQueryResult, { data: T }>` narrows loading vs success states. - Zod: pull specific schema validators from a union of `z.ZodTypeAny`. - tRPC: filter router procedures by input shape. - Role guards: `Extract<AppRole, "admin" | "superadmin">` for protected routes. ### Follow-up questions **Q:** What does `Extract<'a' | 'b', string>` return? **A:** `'a' | 'b'`. Both string literals are assignable to `string`, so both pass through unchanged. **Q:** How is `Extract<T, U>` different from `T & U`? **A:** `&` creates an intersection of properties and can produce `never` on primitive conflicts. `Extract` selects whole union members that fit U, keeping their original shape intact. **Q:** Write `Extract<'a' | 1, string | number>` manually. **A:** `('a' extends string | number ? 'a' : never) | (1 extends string | number ? 1 : never)` equals `'a' | 1`. Both members pass. **Q:** Why is `Extract<{x: 1}, {x: string}>` equal to `never`? **A:** Because `1` is not assignable to `string`. The structural check fails on the `x` property. **Q:** (Senior) How would you implement the inverse of `Extract`? **A:** `Exclude<T, U>` is the built-in inverse. Custom implementation: `T extends U ? never : T`. ## Examples ### Basic: filtering a mixed union ```ts type Event = "click" | "keydown" | "focus" | "drag"; type KeyboardEvents = Extract<Event, "keydown" | "focus">; // "keydown" | "focus" function handleKeyboard(event: KeyboardEvents) { // TypeScript knows event is only "keydown" or "focus" console.log("Keyboard event:", event); } ``` Two string literals pass the filter. The rest are removed from the type. The function signature now reflects only what it actually handles. ### Intermediate: API response handler ```ts type ApiResponse = | { status: "success"; data: string } | { status: "error"; message: string } | null | undefined; type ErrorResponse = Extract<ApiResponse, { status: "error" }>; // { status: "error"; message: string } function handleError(response: ErrorResponse) { console.log("Error:", response.message); // TypeScript knows .message exists here } function processResponse(response: ApiResponse) { if (response && response.status === "error") { handleError(response); // Assignable - the guard narrows to ErrorResponse } } ``` `Extract` gives you a precise type for the error branch. Without it, you would need a type assertion or a manual type guard that TypeScript cannot verify on its own.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.