Open skarab42 opened 1 year ago
Add toThrowError
type Test<T extends number> = T;
// Pass
assertType<Test<string>>().toThrowError();
assertType<Test<string>>().toThrowError(2344);
assertType<Test<string>>().toThrowError('does not satisfy the constraint');
assertType<Test<string>>().toThrowError(/^Type 'string'/);
// Fail
assertType<Test<number>>().toThrowError();
assertType<Test<string>>().toThrowError(2244);
assertType<Test<string>>().toThrowError('poes not satisfy the constraint');
assertType<Test<string>>().toThrowError(/Type 'string'$/);
I'm personally not a big fan of the Jest API, but I'll leave that decision to Sam.
decoupling the expected type from the type to be compared makes the bug https://github.com/SamVerschueren/tsd/issues/142 with generics disappear by design.
How does the problem disappear by design? If it fixes that issue, that is a big benefit of this PR.
decoupling the expected type from the type to be compared makes the bug #142 with generics disappear by design.
How does the problem disappear by design? If it fixes that issue, that is a big benefit of this PR.
I think it does! (since the Actual
type is already baked-into assertType()
, so by the time the generic for Expected
comes into play in .identicalTo()
, the compiler won't alter the inferred typearg based on the expectation)
Would this be a replacement for the existing API? Seems confusing to have two very different ways of using tsd, one of which can tell you everything's ok when it's not. I ask partly because it might be nice to align APIs with expect-type here too - assertType(...).identicalTo(...)
is equivalent to expectTypeOf(...).toEqualTypeOf(...)
, and assertType(...).assignableTo(...)
is equivalent to expectTypeOf(...).toMatchTypeOf(...)
.
Since there are some users of each it could be nice to give them the same API (some people might care more about CLI error messages who'd go for tsd
vs others who might want it to "just work" by running tsc
who'd go for expect-type
).
I think it does! (since the
Actual
type is already baked-intoassertType()
, so by the time the generic forExpected
comes into play in.identicalTo()
, the compiler won't alter the inferred typearg based on the expectation)
That's right. The thing with the current design is that we share the same parameter to test two potentially different types and due to the nature of TS generic inference this can produce unexpected results with optional parameter. As we provide the expected type it will be propagated to parameters that are not defined in the target type.
declare const inferrable: <T = 'SomeDefaultValue'>() => T
function expectType<Expected>(expected: Expected): void {}
expectType<number>(inferrable()); // 'T' is inferred from 'Expected' => number
expectType(inferrable<number>()); // 'Expected' is inferred from 'T' => number
expectType(inferrable()); // Since no parameter was provided 'Expected' is inferred from 'T' default value => 'SomeDefaultValue'
By splitting the expected type and the actual type and ensuring that the user never produces a generic and an argument at the same time the bug no longer occurs.
assertType(foo).assignableTo(bar);
assertType(foo).assignableTo<Bar>();
assertType<Foo>().assignableTo(bar);
assertType<Foo>().assignableTo<Bar>();
assertType<Foo>(bar).assignableTo<Bar>(); // Error: Do not provide a generic type and an argument value at the same time.
assertType<Foo>().assignableTo(); // Error: A generic type or an argument value is required.
Would this be a replacement for the existing API? Seems confusing to have two very different ways of using tsd, one of which can tell you everything's ok when it's not.
This is a very good question. I think they can coexist without any problem for a while to allow a smooth transition. But that's a decision for @SamVerschueren to make (as long as he's happy with the new API).
I ask partly because it might be nice to align APIs with expect-type here too - assertType(...).identicalTo(...) is equivalent to expectTypeOf(...).toEqualTypeOf(...), and assertType(...).assignableTo(...) is equivalent to expectTypeOf(...).toMatchTypeOf(...).
I'm not convinced by this. The names of the methods are literally the names of the TS compiler and they do what they say they do. For example your toMatchTypeOf
is rather a assignableTo
or subtypeOf
than assignableTo
alone.
This PR add a new assertion API.
Planned features
(not.)identicalTo
(not.)assignableTo
(not.)subtypeOf
toThrowError
with code and/or message matching(not.)toBeDeprecated
(not.)toBeInternal
toHaveDocBlock
toHaveDocBlockTag
print
toBeNever
,toBeNull
, ...In addition to being more descriptive, decoupling the expected type from the type to be compared makes the bug #142 with generics disappear by design.