Releases: mmkal/expect-type
v0.17.0
#16 went in to - hopefully - significantly improve the error messages produce on failing assertions. Here's an example of how vitest's failing tests were improved:
Before:
After:
Docs copied from the readme about how to interpret these error messages
Error messages
When types don't match, .toEqualTypeOf
and .toMatchTypeOf
use a special helper type to produce error messages that are as actionable as possible. But there's a bit of an nuance to understanding them. Since the assertions are written "fluently", the failure should be on the "expected" type, not the "actual" type (expect<Actual>().toEqualTypeOf<Expected>()
). This means that type errors can be a little confusing - so this library produces a MismatchInfo
type to try to make explicit what the expectation is. For example:
expectTypeOf({a: 1}).toEqualTypeOf<{a: string}>()
Is an assertion that will fail, since {a: 1}
has type {a: number}
and not {a: string}
. The error message in this case will read something like this:
test/test.ts:999:999 - error TS2344: Type '{ a: string; }' does not satisfy the constraint '{ a: \\"Expected: string, Actual: number\\"; }'.
Types of property 'a' are incompatible.
Type 'string' is not assignable to type '\\"Expected: string, Actual: number\\"'.
999 expectTypeOf({a: 1}).toEqualTypeOf<{a: string}>()
Note that the type constraint reported is a human-readable messaging specifying both the "expected" and "actual" types. Rather than taking the sentence Types of property 'a' are incompatible // Type 'string' is not assignable to type "Expected: string, Actual: number"
literally - just look at the property name ('a'
) and the message: Expected: string, Actual: number
. This will tell you what's wrong, in most cases. Extremely complex types will of course be more effort to debug, and may require some experimentation. Please raise an issue if the error messages are actually misleading.
The toBe...
methods (like toBeString
, toBeNumber
, toBeVoid
etc.) fail by resolving to a non-callable type when the Actual
type under test doesn't match up. For example, the failure for an assertion like expectTypeOf(1).toBeString()
will look something like this:
test/test.ts:999:999 - error TS2349: This expression is not callable.
Type 'ExpectString<number>' has no call signatures.
999 expectTypeOf(1).toBeString()
~~~~~~~~~~
The This expression is not callable
part isn't all that helpful - the meaningful error is the next line, Type 'ExpectString<number> has no call signatures
. This essentially means you passed a number but asserted it should be a string.
If TypeScript added support for "throw" types these error messagess could be improved. Until then they will take a certain amount of squinting.
Concrete "expected" objects vs typeargs
Error messages for an assertion like this:
expectTypeOf({a: 1}).toEqualTypeOf({a: ''})
Will be less helpful than for an assertion like this:
expectTypeOf({a: 1}).toEqualTypeOf<{a: string}>()
This is because the TypeScript compiler needs to infer the typearg for the .toEqualTypeOf({a: ''})
style, and this library can only mark it as a failure by comparing it against a generic Mismatch
type. So, where possible, use a typearg rather than a concrete type for .toEqualTypeOf
and toMatchTypeOf
. If it's much more convenient to compare two concrete types, you can use typeof
:
const one = valueFromFunctionOne({some: {complex: inputs}})
const two = valueFromFunctionTwo({some: {other: inputs}})
expectTypeOf(one).toEqualTypeof<typeof two>()
Kinda-breaking changes: essentially none, but technically, .branded
no longer returns a "full" ExpectTypeOf
instance at compile-time. Previously you could do this:
expectTypeOf<{a: {b: 1} & {c: 1}}>().branded.not.toEqualTypeOf<{a: {b: 1; c: ''}}>()
expectTypeOf<{a: {b: 1} & {c: 1}}>().not.branded.toEqualTypeOf<{a: {b: 1; c: ''}}>()
Now that won't work (and it was always slightly nonsensical), so you'd have to use // @ts-expect-error
instead of not
if you have a negated case where you need branded
:
// @ts-expect-error
expectTypeOf<{a: {b: 1} & {c: 1}}>().branded.not.toEqualTypeOf<{a: {b: 1; c: ''}}>()
What's Changed
- Improve CLI error messages by @mmkal in #16
- expect-type is usually a dev dependency by @SerkanSipahi in #39
New Contributors
- @SerkanSipahi made their first contribution in #39
Full Changelog: v0.16.0...v0.17.0
v0.16.0
What's Changed
- support functions with
this
parameters by @mmkal and @papb in #15 - Prevent the .not modifier from being chained by @trevorade in #20
- Rewrite
Equal
to use the equality check fromReadonlyEquivalent
exclusively by @trevorade in #21
Note that #21 has affected behavior for intersection types, which can result in (arguably) false errors:
// @ts-expect-error the following line doesn't compile, even though the types are arguably the same.
// See https://github.com/mmkal/expect-type/pull/21
expectTypeOf<{a: 1} & {b: 2}>().toEqualTypeOf<{a: 1; b: 2}>()
Full Changelog: v0.15.0...v16.0.0
v0.15.0
What's Changed
- Update Extends to not distribute over union types by @trevorade in #12
New Contributors
- @trevorade made their first contribution in #12
Full Changelog: v0.14.2...v0.15.0
v0.14.2
v0.14.1
Pure docs update
- Mention tsdjs/tsd#142 cd3b522
- lint markdown 026a117
- add badges 929558d
- Create ci.yml d9eecdf
v0.14.0
- minor release from this repo
- previously release from mmkal/ts repo: https://github.com/mmkal/ts/releases/tag/expect-type_v0.13.0 - follow the breadcrumbs from there if interested!
v0.14.0-0
- preminor release for standalone repo
- works around a typescript bug that seems to have been introduced in one of the recent typescript versions