Exclude<Status, "deleted"> is the union Status without the member "deleted"; Extract<Status, "draft" | "live"> keeps only those two. They filter union types, member by member; TypeScript 2.8 added them along with conditional types.
Extract with an object shape picks members of a discriminated union: Extract<UiEvent, { type: "click" }> is the click event type, with its x and y.
At a glance
| Use | JSDoc in a .js file | TypeScript in a .ts file |
|---|---|---|
| Remove members | /** @typedef {Exclude<Status, "deleted">} VisibleStatus */ | type VisibleStatus = Exclude<Status, "deleted">; |
| Keep members | /** @typedef {Extract<Status, "draft" | "live">} EditableStatus */ | type EditableStatus = Extract<Status, "draft" | "live">; |
| Pick a union member by shape | /** @typedef {Extract<UiEvent, { type: "click" }>} ClickEvent */ | type ClickEvent = Extract<UiEvent, { type: "click" }>; |
Examples
status.js status.ts TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026:
No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3.
No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3.
No errors. checked 21 October 2026
/** @typedef {"draft" | "live" | "archived" | "deleted"} Status */
/** @typedef {Exclude<Status, "deleted">} VisibleStatus */
/** @typedef {Extract<Status, "draft" | "live">} EditableStatus */
/**
* @typedef {{ type: "click", x: number, y: number }
* | { type: "key", key: string }
* | { type: "scroll", top: number }} UiEvent
*/
/** @typedef {Extract<UiEvent, { type: "click" }>} ClickEvent */
/** @param {VisibleStatus} status */
export function badge(status) {
return status.toUpperCase();
}
/** @param {ClickEvent} event */
export function where(event) {
return `${event.x},${event.y}`;
}
/** @type {EditableStatus} */
const editable = "draft";
badge(editable);
where({ type: "click", x: 10, y: 20 });type Status = "draft" | "live" | "archived" | "deleted";
type VisibleStatus = Exclude<Status, "deleted">;
type EditableStatus = Extract<Status, "draft" | "live">;
type UiEvent = { type: "click"; x: number; y: number } | { type: "key"; key: string } | { type: "scroll"; top: number };
type ClickEvent = Extract<UiEvent, { type: "click" }>;
export function badge(status: VisibleStatus) {
return status.toUpperCase();
}
export function where(event: ClickEvent) {
return `${event.x},${event.y}`;
}
const editable: EditableStatus = "draft";
badge(editable);
where({ type: "click", x: 10, y: 20 });jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} status.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026:
status.js(10,7): error TS2345: Argument of type '"deleted"' is not assignable to parameter of type '"draft" | "live" | "archived"'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3.
status.js(10,7): error TS2345: Argument of type '"deleted"' is not assignable to parameter of type '"draft" | "live" | "archived"'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3.
status.js(10,7): error TS2345: Argument of type '"deleted"' is not assignable to parameter of type 'VisibleStatus'. checked 21 October 2026
/** @typedef {"draft" | "live" | "archived" | "deleted"} Status */
/** @typedef {Exclude<Status, "deleted">} VisibleStatus */
/** @param {VisibleStatus} status */
export function badge(status) {
return status.toUpperCase();
}
badge("deleted");error TS2345: Argument of type '"deleted"' is not assignable to parameter of type '"draft" | "live" | "archived"'.jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} They work on unions
Both are distributive conditional types, so they act on each member of a union. They are not for object properties: to drop a property from an object type, use Omit; to keep some, Pick.
Gotchas
- Neither checks that
Umatches anything.Exclude<Status, "delted">silently removes nothing. NonNullable<T>is the special caseExclude<T, null | undefined>.
Questions
What is the difference between Exclude and Omit?
Exclude removes members from a union type; Omit removes properties from an object type.
Sources
- Utility Types: Exclude and Extract · TypeScript handbook
- TypeScript 2.8: predefined conditional types · TypeScript release notes
Last reviewed 20 October 2026.