Skip to main content

TypeScript: Assertions

Assertions

In TypeScript, assertions are expressions used to inform the TypeScript compiler about the type of a variable or expression when the type is known to you but cannot be automatically inferred by the compiler. Assertions are a way to provide explicit type information, essentially overriding TypeScript's inherent type inference mechanisms.

Here are the built-in assertions in TypeScript.

as const

The as const assertion converts a variable to a constant, making all its properties readonly.

let example = { x: 10, y: 20 } as const;
// example
x = 15; // Error: Cannot assign to 'x' because it is a read-only property.

as [type]

The as [type] assertion specifies the type of an expression where the type is known but TypeScript cannot infer it.

let someValue: any = "This is a string";
let strLength: number = (someValue as string).length;

another example

interface Person {
name: string;
age: number;
}

// Let's say we have a variable `unknownPerson` of type `any`:
let unknownPerson: any = { name: "Alice", age: 30 };

// We know more about the type, so we assert it to the `Person` type:
let person: Person = unknownPerson as Person;

console.log(person.name); // Output: Alice
console.log(person.age); // Output: 30

as any

The as any assertion opts-out of type checking for a variable.

let vaguelyTyped: any = "could be anything";
let strLength: number = (vaguelyTyped as any).length;

Non-null Assertions

Non-null assertions are a way to tell the TypeScript compiler that you are certain a value will not be null or undefined at the time it is used, even when TypeScript's type checking might consider such a case possible. This assertion can be particularly useful when you are confident about the presence of a value due to the logic of your application, but TypeScript's static analysis cannot infer this certainty.

Syntax of Non-null Assertions

  1. Postfix ! Operator: Placed after the variable or expression, it removes null and undefined from the type.
  2. Using as Type Assertion: Explicitly asserting that the variable is not null or undefined.

Example Usage

// Assume we have an optional interface property which may be undefined
interface User {
id: number;
name?: string;
}

let user: User = { id: 123 };

// Using the non-null assertion to access 'name' which is optionally undefined
let userName: string = user.name!; // We assert that name is definitely not null or undefined here

// Using 'as' type assertion
let userName2: string = user.name as string; // Similarly asserting non-nullability

console.log(userName); // Note: This will throw a runtime error if name is actually undefined

Satisfies Keyword

The satisfies keyword in TypeScript is a relatively new feature introduced in TypeScript 4.9.

It is used for type assertion, allowing you to check if a value satisfies a particular type without changing the resulting type of the expression.

This keyword is particularly useful in situations where you want to ensure that a value conforms to a specific interface or type, but you don't want to change its original type.

Purpose of the satisfies Keyword

The satisfies keyword helps with:

  • Type-checking against an interface or type: Ensuring that a value matches a specific structure without altering its type.
  • Ensuring API contract compliance: Useful when implementing a function or component expected to meet certain type requirements.
  • Documentation and readability: Clearly communicates the intended type conformity without affecting the underlying type of the data.

How It Works

The satisfies keyword acts like a type assertion but does not perform type casting. Instead, it checks that the value can be assigned to the type specified after satisfies and if not, TypeScript will raise a type error at compile time. However, the expression itself still retains its original type.

Example Usage

interface User {
id: number;
name: string;
email: string;
}

const user = {
id: 1,
name: "Alice",
email: "alice@example.com",
isAdmin: true,
};

// Using 'satisfies' to ensure 'user' matches the 'User' interface
user satisfies User;

// 'user' still retains its original type with 'isAdmin' property
console.log(user.isAdmin); // Outputs: true

// If we mistakenly add or omit a property, TypeScript will throw an error
const newUser = {
id: 2,
name: "Bob",
// email is missing here
isAdmin: false,
} satisfies User; // TypeScript Error: Property 'email' is missing in type ...

When to Use satisfies

  • Validating Shape without Narrowing: Use it when you need to validate that an object meets a specific type interface without wanting to narrow the type of the object to that interface.
  • Advanced Configuration Objects: Particularly useful for configuration objects where you expect certain properties to meet specific criteria.
  • Complex Conditions: Where multiple types or interfaces may apply to a single object, and you need to ensure it meets one of them without affecting its usability elsewhere in your code.

Comments