When accessing external APIs or array indices, values may become undefined, making them difficult to handle as-is in terms of type. Use non-null assertions to achieve both runtime checks and type narrowing.
Code
function assertIsDefined<T>(value: T): asserts value is NonNullable<T> { if (value === undefined || value === null) { throw new Error(`Expected 'value' to be defined, but received ${value}`); }}
function nonNull<T>(value: T): NonNullable<T> { assertIsDefined(value); return value;}Usage Examples
Safe Array Element Access
const arr = [1, 2, 3];const value = arr[10]; // number | undefined
// Cannot avoid type errorconsole.log(value.toFixed()); // Error: Object is possibly 'undefined'
// Using nonNullconst safeValue = nonNull(arr[10]);// Inferred as NonNullable<number>console.log(safeValue.toFixed()); // OKAPI Response Validation
interface User { name: string;}
async function getUser(id: string): Promise<User> { const response = await fetch(`/api/users/${id}`); const user = await response.json() as User | undefined;
// Error if response is empty assertIsDefined(user);
// user can be treated as User type at this point return user;}Difference from the ! Operator
TypeScript has a non-null assertion operator value!, but this does not perform runtime checks. Using assertion functions allows you to validate values at runtime while also narrowing the type.
Cautions
Use assertion functions only when you are confident that a value truly exists. Careless use will result in runtime errors. Especially for array index access, consider checking length beforehand.
hsb.horse