Version v1.10.0 of
the @kensio/smartass
package introduces composable type narrowing matchers.
This allows you to apply structured assertions that provide detailed type narrowing back to TypeScript:
import {
assertObjectMatches,
arrayIncluding,
oneOf,
stringOfLength,
} from "@kensio/smartass";
const user = getUser();
assertObjectMatches(user, {
role: oneOf(["admin", "editor", "viewer"]),
tags: arrayIncluding("beta"),
id: stringOfLength(8),
});
// TypeScript knows:
// user.role is 'admin' | 'editor' | 'viewer'
// user.tags is an array with at least one string element
// user.id is a string of length 8 with safe indexing
As with the standalone type narrowing assertion functions, this is made possible by TypeScript’s assertion signature feature.
The fluent expectation interfaces in Jest and Vitest are not able to provide that type narrowing effect back to the compiler, because TypeScript cannot follow an assertion signature through a fluent interface like:
import { expect } from "vitest";
expect(user).toMatchObject({
role: "editor",
});
Due to the expect().toMatchObject() chain, we lose the chance to provide an assertion signature to
TypeScript. It seems like a shame to miss out on the benefit of that type information, so
@kensio/smartass now provides composable type narrowing matchers.
The assertObjectMatches function applies a deep partial match, so you only need to specify the properties that a particular test case is interested in.
After calling that assertion function, you can use the narrowed types for the rest of the test. This tends to reduce the amount of boilerplate code that is required in each test case, which makes the tests more readable and easier to maintain.
As of version v1.10.0, the following type narrowing matcher functions are available:
- arrayIncludingAll
- arrayIncluding
- arrayOfLength
- arrayOfMinLength
- nonEmptyArray
- bufferEqualTo
- instanceOf
- nonNullable
- numberBetween
- numberToNearest
- objectWithProperty
- oneOf
- stringEndingWith
- stringIncluding
- stringOfLength
- stringNotIncluding
- stringStartingWith
- typeBigInt
- typeBoolean
- typeFunction
- typeNumber
- typeNumeric
- typeObject
- typeString
- typeSymbol
- typeTypedArray
- uuidV4
These can be composed together in partial structures for precise type narrowing assertions in tests.