Assertions: How to Assert Conditions and Types
Tags: typescript, javascript, node, tutorial
Published: 2023-07-28 08:34:01

The `asserts` statement was introduced in [TypeScript 3.7](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions). It's a special type of function signature that tells the TypeScript compiler that a particular condition is true from that point on. Essentially, assertions serve as macros for `if-then-error` statements, allowing us to encapsulate precondition checks at the beginning of function blocks, enhancing the predictability and stability of our code.

## Basic Assertions
Consider a basic assertion that checks for a truthy condition. Pay attention to the return type of the function.

```ts
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg);
  }
}
```

The `asserts condition` return type within this function signals to TypeScript that, given the function's successful execution, the provided `condition` is true. Otherwise, an error will be thrown with the specified message.

Here's how this `assert` function can be used to check unknown parameters:

```ts
type Point = { 
  x: number; 
  y: number 
};

function point(x: unknown, y: unknown): Point {
  assert(typeof x === 'number', 'x is not a number');
  assert(typeof y === 'number', 'y is not a number');

  //> from here on, we know that `x` and `y` are numbers
  return { x, y };
}
```

TypeScript evaluates the condition `typeof x === number` and infers the appropriate type for the parameters. After the `assert` calls, TypeScript is aware that `x` and `y` are numbers.

## Asserting Specific Types
Beyond asserting a condition, the `asserts` keyword can validate that a variable matches a specific type. This is achieved by appending a type guard after `asserts`.

Consider the following example:

```ts
function assertPoint(val: unknown): asserts val is Point {
  if (typeof val === 'object' && 'x' in val && 'y' in val && typeof val.x === 'number' && typeof val.y === 'number') {
    return;
  }

  throw new Error('val is not a Point');
}
```

If the `assertPoint` function executes without errors, TypeScript assumes that `val` is a `Point`. This knowledge is retained throughout the block, as demonstrated in this function:

```ts
function print(point: unknown) {
  assertPoint(point);

  //> from here on, we know that `p` is a Point
  console.log(`Position X=${point.x} Y={point.y}`);
}
```

## Asserting Complex Types
The `asserts` isn't confined to simple types or distinct conditions. It also enables us to assert more intricate types. One such example is ensuring a value is defined using TypeScript's `NonNullable<T>` utility type.

Let's consider the following example:

```ts
function assertNonNull<T>(val: T): asserts val is NonNullable<T> {
  if (val === undefined || val === null) {
    throw new Error(`val is ${val === undefined ? 'undefined' : 'null'}`);
  }
}
```

Here, the `assertNonNull` function verifies that the supplied value is neither `null` nor `undefined`. The return type `asserts val is NonNullable<T>` signals to TypeScript that if the function successfully executes, `val` has a defined value.

Lastly, this example demonstrates how this assertion can be paired with the prior one to check multiple conditions:

```ts
function move(point?: unknown) {
  assertNonNull(point);
  assertPoint(point);

  // > from here on, we know that `point` is defined and is a Point
  console.log(`Moving to ${point.x}, ${point.y}`);
}

```

Here, the two assertions at the beginning of the function help TypeScript to gain knowledge about the nature of the given parameter. After these conditions, TypeScript knows that point is defined and it's an object of type `Point`.

If you're intrigued by assertions and wish to learn more, I recommend exploring the [GitHub PR](https://github.com/microsoft/TypeScript/pull/32695) that brought assertions into TypeScript. For a quick hands-on experience, head over to the [Playground](https://www.typescriptlang.org/play?#code/PTAEHEEsDcFMDtQCkCG0UGUDGAnSAHAFwHIBnUAMwBtYAPSAI0iskIE8AaUV0LFRBrFApQAcwD24gCbcpsEYXHCpUgFAhQOAK7xCkALZCsAC1hYA1uUWg24rTl7Sh19CykpCQ2-eGlSW-SJIcXhSADpVdTAAFVNSIRQcZzZ8SD4qKjZeFAzYGRQ-WBw9EPIACnEHSHh0PH5CUgBKYXg1DUJTLMShUn0cqkodLBLQ0AB3YzTjTRRIeNAinEryeRxM8dN4KJs7B1rIFAYacikQ4kJQPsITUC18UGsJjx2tBdp8M0II7YA5J0dDOQxqxpiIKEMRpRKqBTtVRA9JuQ7BdxBQEUIGOJaBxtqwyNlcvlCsUWjI8eQ0LMqIcaOMQciWtxApUvpENAB1WDEJJicRwh5KOQUapCXagcRjRAdOyiYxhUCxOYwszUpIU7bg+DDYKICZTXzxYpWYzPDpCOj4NWkHUEmhtMCuLRCJWEbSwABcqjkWFVQk12pCBqKhDKjo9t3g5ngEvgjXdQaNoDDAG42WA-mNxlyeVp5jwXDlIO5POiHilRWj+At4AEvSruo5Qhc+mxBBhXXCAPI4H4BQQ4eOkDvweEAH1ANf0-dTBUNIfYH1RlxQrdg7bwI+7vanRVAAF4D6AAERDjeiI+NVPbdkghXl7B4IigADMYQA7FwzY45JQqBKWjkbDWuQfCILmzhxLA2wLrASJov6IxWEowqiPYopaBcTwXF+WD-HM8oYOIOIaBMCAvKAxjiHADhUbuX77DSGKwH+mYALTkaBoDxBBHi4hcJrkIIZHwIkSxjHklBLPowhccO8LQpO-YCtsABWuYXCIp5wt8LZtnJW59kUV4aAAmnY2RgfMs7BjaCE6khy7mEIqGJPUsCweKFDbN4DgwcaSxaLKDI+dw8AUIsEm4XIXAUNCdAoIENDbNE964AQFxRhKxqmoigxapCwIZJosCEPYiAoNsim7sC0oYaW8DuTI1goCoZYfA5X74K5hieDg2zQAcpaHLRCYXN6qoeDq3x2YG+haFQej4JkZS0PG-CcDYa3wGwzQAN6qKAo1lDBS60Puh5HlVOAXqmh3WcUx3lkuWQHnux5XTdkSHUkpU4IgZ0AFQ2KmAC+aagAAgsSkIzaMDbWkccIOSlHwQFoiRSKQ2zxYlHowaxLk4JjbxYLAT5ml0FDhcMpa4boSwDNQErbKRiA8HTeg1h5HQBbKpaw98GgAGJxbQCVLbAXDiRZtxWdDtkQvZAoTqJzMaFWCABDCMbitRDwGB6kTjQ2dNDuKDWdhQQuQDgQ7W3A279qQ8YAIygOOABM7svt7AAs3sAKxXsbPKw9wpCdioZRdTgCXxjomWSnGo3kDHCXh6Abvjs+gepiHfqK4GcwAELMRKIv2NH3Xx5G0ZJ2t0Op91GdZ6AXvZ37xkxLlpCUfNMhYHVpySqWmvSYorvezn44B5EcyR1IFQW1bNt2zAsCO0UTSpiEsCW9btuEPbG+GbbXcKrlhUDGaiCD9hpjVgE+L4OIfiMLSQ4eNz4iT9nc+kKXFiFccBLz3ivQ+x9N620vKoXe+9V5H3XlA0g59FTkCVCIS0BsaKIFIOIQwnl+byF+h5Jc90YaF1CLiRAKM1xpSfK+N8oB2LeBlsKVo4o6r6EqBiLISQWr8jNNsJINAChCGjJ4Z2URtjGEIIQfAzsQByGgEccQohwj6DSEsPBFAvi4X0MAPy9DCDAH4NGIYcJWJGMfIQViz5WJvmAEAA) from Microsoft.

{% embed https://github.com/microsoft/TypeScript/pull/32695 %}

---

I hope you found this post helpful. If you have any questions or comments, feel free to leave them below. If you'd like to connect with me, you can find me on [LinkedIn](https://www.linkedin.com/in/christian-zirkel/) or [GitHub](https://github.com/zirkelc). Thanks for reading!