Reputation: 29989
Why does the extends clause succeed when checking whether a 0-arity function extends a 1-arity type?
Is there any way to make the first form work?
The same check on tuples works as I'd expect, so I can use Parameters
instead, but I'm curious as to why.
function foo(bar: number) {
// ...
}
function baz() {
// ...
}
type Foo = typeof foo extends (bar: infer T) => void ? T : never; // number - expected number
type Baz = typeof baz extends (bar: infer T) => void ? T : never; // unknown - expected never
type Foo2 = Parameters<typeof foo> extends [infer T] ? T : never; // number - ok
type Baz2 = Parameters<typeof baz> extends [infer T] ? T : never; // never - ok
Upvotes: 1
Views: 49
Reputation: 1905
I find this behavior strange myself, but the issue is that TypeScript says that less parameters is a subtype of more parameters. What this means is that () => void
extends (x: number) => void
, but not vice versa. TypeScript doesn't know the value of the parameter in type Baz
(since there are no parameters in typeof baz
) so it says the extends
clause is true and sets T
to unknown
.
On the other hand, tuple types can't really extend each other unless the type in each index of the subtype tuple extend the value of the corresponding index in the supertype tuple (i.e. it's true that [number & string, number] extends [number, number]
). That means when there are a different number of parameters, the extends
clause always returns false and makes your second example work.
This is definitely pretty confusing, so here's a playground showing the difference.
Upvotes: 1