NonNullable<Type>
Removes null and undefined from a type, leaving only its definitely-present members.
type NonNullable<Type> = Type & {}- Added in TypeScript 2.8
Parameters
| Parameter | Type | Description |
|---|---|---|
$Type | any type | The type to strip nullish members from. Under `strictNullChecks: false` this is a no-op, because null and undefined are already absent from every union. |
Return value
Type with null and undefined removedThe intersection of Type with the empty object type, which reduces away `null` and `undefined` because neither is assignable to `{}`.
Errors
Nothing at runtime. The checker errors when a nullish value is assigned to the resulting type.
Changelog
- PHP 4.8Reimplemented from the conditional `Type extends null | undefined ? never : Type` to the intersection `Type & {}`. Intersections reduce and can be assigned to where conditional types cannot, so nested applications now simplify — but `NonNullable<unknown>` is now `{}` rather than `unknown`.
NonNullable strips null and undefined. Since TypeScript 4.8 it is implemented as Type & {}: nothing in JavaScript is both null and an object, and nothing is both undefined and an object, so those members reduce away while every other member survives the intersection unchanged.
It only does anything under strictNullChecks
With strictNullChecks: false, null and undefined are assignable to every type and are not tracked in unions, so there is nothing for NonNullable to remove — it is a no-op, and code that relies on it for safety has none. This is the first thing to check when the type looks right but a Cannot read properties of undefined still reaches production.
When to reach for it
- Naming the payload type of an optional field:
NonNullable<Response["data"]>. - Writing the return type of a filter predicate:
(v): v is NonNullable<T> => v != null. - Composing inside a mapped type to strip nullishness from every property at once.
What trips people up
It does not filter values. The type says the nulls are gone; only a runtime filter actually removes them, and Array.prototype.filter will not narrow the element type unless you give it a type predicate.
Example
When to use it
- Give a name to the non-null payload type of an optional API response field.
- Write a `.filter()` type predicate that narrows `(T | null)[]` down to `T[]`.
- Strip nullishness from every property of a type inside a mapped type.
Frequently asked questions
How do I remove null and undefined from a type?
Wrap it in `NonNullable<T>`, which since TypeScript 4.8 is implemented as `T & {}` — the intersection eliminates `null` and `undefined` because neither is assignable to `{}`.
Why does NonNullable seem to do nothing?
Almost always because `strictNullChecks` is off. Without it, `null` and `undefined` are assignable everywhere and never appear in unions, so there is nothing to strip. Turn on `strict` or `strictNullChecks` in tsconfig.json.
How do I filter nulls out of an array and get the narrowed type?
Give `.filter()` a type predicate: `items.filter((x): x is NonNullable<typeof x> => x != null)`. A plain `filter(Boolean)` removes the values at runtime but leaves the element type unchanged, and also drops `0` and `""`.
More examples
Naming the payload of an optional field
Prints `#a1: 12`, `no data (404)`, `#a2: 7`. `Payload` is derived rather than redeclared, so widening the `data` shape in the interface updates `render`'s parameter automatically. The `response.data ?` guard is still required — `NonNullable` describes the type after the check, it does not perform one.
interface ApiResponse {
status: number;
data?: { id: string; total: number } | null;
error?: string;
}
// One source of truth for the payload shape.
type Payload = NonNullable<ApiResponse["data"]>;
function render(payload: Payload): string {
return `#${payload.id}: ${payload.total}`;
}
const responses: ApiResponse[] = [
{ status: 200, data: { id: "a1", total: 12 } },
{ status: 404, data: null },
{ status: 200, data: { id: "a2", total: 7 } },
];
for (const response of responses) {
console.log(response.data ? render(response.data) : `no data (${response.status})`);
}Stripping nullishness from every property
Prints `{ name: 'Ada', age: 36, nickname: 'AL' }` and then `null`. The mapped type combines two modifiers: `-?` removes the optional marker on `nickname`, and `NonNullable` removes the explicit `| null` from each property type. Neither alone is enough — `-?` does not touch a declared `null`, and `NonNullable` does not remove an optional marker.
interface FormValues {
name: string | null;
age: number | null;
nickname?: string | null;
}
type Submitted = { [K in keyof FormValues]-?: NonNullable<FormValues[K]> };
// Submitted is { name: string; age: number; nickname: string }
function validate(values: FormValues): Submitted | null {
const { name, age, nickname } = values;
if (name == null || age == null || nickname == null) return null;
return { name, age, nickname };
}
console.log(validate({ name: "Ada", age: 36, nickname: "AL" }));
console.log(validate({ name: "Ada", age: null, nickname: "AL" }));
Discussion