Open Yarmeli opened 9 months ago
Did you try:
expectNotAssignable<myCustomType>({ value: [1 as const] });
I tried that and that approach works, but it kind of looks a bit meeh to do something like this:
expectNotAssignable<myCustomType>({ value: [1 as const, 1 as const, 1 as const] });
For a slightly longer type, I feel there are way too many as const
needed to test and it isn't intuitive that as const
should be used
type myCustomType = {
simple: 1;
optional: 2 | null;
list: 3[];
}
expectAssignable<myCustomType>({
simple: 1,
optional: 2,
list: [3, 3, 3]
}); // ✅ it passes, but should this have 'as const' as well?
expectNotAssignable<myCustomType>({
simple: 1 as const,
optional: 2 as const,
list: [3 as const, 3 as const, 3 as const]
}); // ✅ only way to make it fails as expected
expectNotAssignable<myCustomType>({
simple: 1, // not made 'as const'
optional: 2 as const,
list: [3 as const, 3 as const, 3 as const]
}); // ❌ it passes when it should fail
expectNotAssignable<myCustomType>({
simple: 1 as const,
optional: 2, // not made 'as const'
list: [3 as const, 3 as const, 3 as const]
}); // ❌ it passes when it should fail
expectNotAssignable<myCustomType>({
simple: 1, // not made 'as const'
optional: 2, // not made 'as const'
list: [3 as const, 3 as const, 3 as const]
}); // ❌ it passes when it should fail
expectNotAssignable<myCustomType>({
// make the full object 'as const'
simple: 1,
optional: 2,
list: [3, 3, 3]
} as const); // ❌ it passes when it should fail
Thoughts?
Thanks for asking. It is always interesting to talk about type testing.
Please note that I am not associated with tsd
. It was used to test typings in Jest repo and I was contributing a lot of type tests. Limitations and issues of the library pushed me to create tsd-lite
fork. It does not have the issue you are wrestling with, but at this moment I do not recommend migrating to tsd-lite
.
It is going to be replaced by brand new type testing tool, which I will publish in about a week. It is written from scratch, the architecture is different and all that helps to solve limitations which tsd-lite
inherited. For instance, it is enough to pass a CLI flag to test on several versions of TypeScript (see: https://github.com/jest-community/jest-runner-tsd/issues/32#issuecomment-1228738812).
Back to your problem. What do you mean by “slightly longer type”? In this case { value: [1 as const] }
is not a type, this is an expression. tsd
is using TypeScript’s APIs to infer type of expression and compares it with the one you pass as type argument.
To check how type information is inferred, you can use hover information:
But:
That is just how TypeScript works. Use as const
:
All this is simple and obvious, of course. (Might be even intuitive, but that’s rather subjective.)
The problem is that tsd
s expectAssignable
infers type of an expression like this:
But expectNotAssignable
infers type of the same expression like this:
In a way, expectAssignable
already knows what is expected. In my opinion, the behaviour of expectAssignable
is broken. (By the way, it is the cause of #142 as well.) This is not a problem for tsd-lite
. It was easy to fix.
Hope this explains the inconsistency of behaviour between expectAssignable
and expectNotAssignable
.
Gotcha, thanks for the explanation 😄
By “slightly longer type”, I meant this:
type myCustomType = {
simple: 1;
optional: 2 | null;
list: 3[];
}
In the initial version where myCustomType
only had a single key value
, the idea to mark the array items as const wouldn't be too much of a hassle (i.e. { value: [1 as const] }
), buuuut for the longer objects with more keys and at least one array, it becomes more of a hassle to declare every single thing as const
since you can't just declare the full object as const
as that would make the array readonly
// I'd prefer to do something like this (which doesn't work)
expectNotAssignable<myCustomType>({
simple: 1,
optional: 2,
list: [3, 3, 3]
} as const);
// Instead of marking everything as const
expectNotAssignable<myCustomType>({
simple: 1 as const,
optional: 2 as const,
list: [3 as const, 3 as const, 3 as const]
});
I kind of expected expectNotAssignable
to behave the same way as expectAssignable
since we pass the type to each of them - instead of inferring the type as number
, use the type that I gave you (if my type is number
use that, if it is 1
use that instead)
Looking forward to tsd-lite
Hey
I noticed that the behaviour for
expectAssignable
andexpectNotAssignable
seems wrong for arraysHere are a few examples;
✅ Works as expected
❌ Fails
I saw that in #190 a suggested fix would be to use
as const
but this doesn't really work with arraysAny suggestions?