TypeScript Assertion Signatures


Typescript 3.7 introduced some cracking features such as optional chaining and nullish coalescing. There was another useful feature that TypeScript 3.7 introduced, which is called assertion signatures. In this post, we’ll find out what assertion signatures are and where we can use them.

Type guard with a type predicate

Let’s say we have the following type for various editor elements a field can have:

type Editor =
| HTMLInputElement
| HTMLSelectElement;

So, the editor element can be an input element or a select element.

We need to implement a function that gets the value if the editor element is a checkbox. Here’s how we could do this before TypeScript 3.7 with a type predicate:

function getCheckboxValue(editor: Editor) {
if (isCheckbox(editor)) {
// type of editor narrowed to HTMLInputElement
return editor.checked;
}
throw new Error("editor is not a checkbox");
}
function isCheckbox(
editor: Editor
): editor is HTMLInputElement {
return "checked" in editor;
}

The getCheckboxValue function takes in a parameter called editor of type Editor. Inside the if condition, the type of the editor parameter has been narrowed to HTMLInputElement. This means that TypeScript is happy with the checked property in editor.

Here, the isCheckbox type predicate is used to narrow the type of editor to HTMLInputElement. The return type annotation, editor is HTMLInputElement tells TypeScript that the type of editor can be narrowed to HTMLInputElement when the function returns true.

Type guard using an assertion signature

An assertion signature is an alternative approach for implementing a type guard. Let’s give this a go:

function getCheckboxValue(editor: Editor) {
assertIsCheckbox(editor);
// type of editor narrowed to HTMLInputElement
return editor.checked;
}
function assertIsCheckbox(
editor: Editor
): asserts editor is HTMLInputElement {
if (!("checked" in editor)) {
throw new Error("Not a checkbox");
}
}

The assertion signature is in the assertIsCheckbox function, in the return type annotation. This is asserts editor is HTMLInputElement in our example which results in editor being narrowed to HTMLInputElement after this function has been returned.

Type guard using a general assert function

We can implement a general assert function which contains an assertion signature as follows:

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

This tells TypeScript that whatever gets passed into the condition parameter must be true if the function returns (because otherwise, it would throw an error).

We can use it in getCheckboxValue function as follows:

function getCheckboxValue(editor: Editor) {
assert(
"checked" in editor,
"editor is not a checkbox"
);
// type of editor narrowed to HTMLInputElement
return editor.checked;
}

Wrap up

An assertion signature is a way of implementing a type guard to narrow the type of a variable. It is arguably closer to standard JavaScript constructs than using a type predicate.

Learn React with TypeScript - 3rd Edition

New

A comprehensive guide to building modern React applications with TypeScript. Learn best practices, advanced patterns, and real-world development techniques.

View on Amazon
Learn React with TypeScript - Third Edition