I'm using a type-level Assert
function to make assertions about the type-inferencing in my code. However, I'm not able to make any assertions about a type not being any
.
type Assert<A extends ShouldBe, ShouldBe> = A
// @ts-expect-error
type SubsetObj = Assert<{ id: string }, { id: string; name: string }>
type SameObj = Assert<
{ id: string; name: string },
{ id: string; name: string }
>
type ExceedsObj = Assert<{ id: string; name: string }, { id: string }>
type SubsetUnion = Assert<number, number | string>
type SameUnion = Assert<number | string, number | string>
// @ts-expect-error
type ExceedUnion = Assert<number | string, number>
// @ts-expect-error 👈 this is what I want to work.
type AnyShouldWork = Assert<any, number>
I've tried a few things with no avail. I noticed that unknown
works as expected
// @ts-expect-error
type AssertUnknown = Assert<unknown, number>
And so I tried this code:
type IsAny<T> = unknown extends T ? (T extends {} ? T : never) : never
type NotAny<T> = T extends IsAny<T> ? unknown : T
type Assert2<A extends ShouldBe, ShouldBe> = Assert<NotAny<A>, ShouldBe>
// @ts-expect-error
type AssertAny = Assert2<any, number>
But this doesn't work because Assert<NotAny<A>, ShouldBe>
fails right off the bat because NotAny
can return unknown...
So I'm kind of stuck here... Any ideas?
I think it is better and much easier to use extra Equals
helper:
// credits goes to https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650
export type Equals<X, Y> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : false;
type AssertTrue<A extends true> = A
// @ts-expect-error
type Test1 = AssertTrue<Equals<any, number>>
// @ts-expect-error
type Test2 = AssertTrue<Equals<unknown, number>>
// @ts-expect-error
type Test3 = AssertTrue<Equals<number | string, number>>
// @ts-expect-error
type Test4 = AssertTrue<Equals<{ id: string }, { id: string; name: string }>>