Open davidsu opened 2 years ago
T2
is a type, and {a:{b:1}}
argument is a value. In different contexts, TypeScript can infer different types for the same value.
expectType
is declared as export const expectType = <T>(expression: T) => {}
- its parameter type is explicitly declared to be the same as the generic type parameter, so {a: {b: 1}}
literal argument has type T2
which is the same {a: {b: 1}}
, and the types match.
expectNotType
is declared as export const expectNotType = <T>(expression: any) => {}
, its parameter type is any
and literal argument type is widened to {a: {b: number}}
, which is different from T2
, and the types do not match.
From TypeScript point of view, everything works as expected.
Widening can be suppressed by using as const
cast for the argument: expectNotType<T2>({a:{b:1}} as const)
fails.
But from the user point of view, it's hard to justify why as const
is needed to avoid situation when both seemingly opposite assertions are true.
I don't know if there's any other way to fix this besides choosing entirely different API for assertions. If the purpose is to test types, the assertions should use types, not values - one possible API could be
assertType<T2>().assignableTo<{a: {b: 1}}>();
assertType<T2>().notAssignableTo<{a: {b: 1}}>();
where functions do not take any arguments - for testing types of values, one will have to use .assignableTo<typeof someValue>
I'd think that const
type parameters coming in TS 5.0 (microsoft/TypeScript#51865, TS 5.0 RC announcement) would help solve this issue.
Related discussion about API changes in #168.
See #196 for discussion on this.
This is an amazing library, thanks for it. can you pls explain why this pass?
I'd expect
expectNotType<T2>({a:{b:1}})
andexpectNotAssignable<T2>({a:{b:1}})
to fail. thanks a lot.