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.
If you to learn more about using TypeScript with React, you may find my course useful: