NonNullable<T> is T without null and undefined. NonNullable<Product["discount"]> is number when the discount property is number | null | undefined, which is the right type for the value after ?? 0.
Assigning null to it is an error (TS2322), as the first example shows. TypeScript 2.8 added it with the other predefined conditional types.
At a glance
| JSDoc in a .js file | TypeScript in a .ts file |
|---|---|
/** @type {NonNullable<Product["discount"]>} */ | : NonNullable<Product["discount"]> |
Examples
products.js products.ts Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026:
products.js(14,7): error TS2322: Type 'null' is not assignable to type 'number'.
products.ts(9,7): error TS2322: Type 'null' is not assignable to type 'number'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3.
products.js(14,7): error TS2322: Type 'null' is not assignable to type 'number'.
products.ts(9,7): error TS2322: Type 'null' is not assignable to type 'number'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3.
products.js(14,7): error TS2322: Type 'null' is not assignable to type 'number'.
products.ts(9,7): error TS2322: Type 'null' is not assignable to type 'number'. checked 21 October 2026
/** @typedef {{ sku: string, discount: number | null | undefined }} Product */
/** @typedef {NonNullable<Product["discount"]>} Discount */
/**
* @param {Product} product
* @returns {Discount}
*/
export function discountOf(product) {
return product.discount ?? 0;
}
/** @type {Discount} */
const none = null;error TS2322: Type 'null' is not assignable to type 'number'.
export { none };type Product = { sku: string; discount: number | null | undefined };
type Discount = NonNullable<Product["discount"]>;
export function discountOf(product: Product): Discount {
return product.discount ?? 0;
}
const none: Discount = null;error TS2322: Type 'null' is not assignable to type 'number'.
export { none };jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} compact.js 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
/**
* @template T
* @param {T[]} items
* @returns {NonNullable<T>[]}
*/
export function compact(items) {
return items.filter(/** @returns {item is NonNullable<T>} */ (item) => item != null);
}
const skus = compact(["TEE-01", null, "MUG-07", undefined]);
skus.map((sku) => sku.toLowerCase());jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} In generic helpers
A compact helper that drops empty values returns NonNullable<T>[]. The filter callback needs a type predicate, item is NonNullable<T>, so that TypeScript accepts the narrowed array as the return value; the second example writes it in a JSDoc comment on the arrow function.
Gotchas
- Without
strictorstrictNullChecks,nullandundefinedare not tracked andNonNullablechanges nothing visible. - It removes only
nullandundefined;0,""andfalsestay.
Questions
How do I remove null from a type in JSDoc?
{NonNullable<YourType>}, or write the type without null if you control it.
Sources
- Utility Types: NonNullable<Type> · TypeScript handbook
- TypeScript 2.8: predefined conditional types · TypeScript release notes
Last reviewed 20 October 2026.