typescripttypescript-genericstype-assertion

How to type-level assert a type is not any?


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?


Solution

  • 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 }>>