Reputation: 26243
class Base {}
function log(arg: number) {
console.log(arg);
}
function fn<T extends typeof Base>(
instance: Partial<InstanceType<T>>,
key: keyof InstanceType<T>,
) {
const val = instance[key];
if (val) {
log(val);
}
}
I get:
Argument of type 'InstanceType<T>[keyof InstanceType<T>] | undefined' is not assignable to parameter of type 'number'.
Type 'undefined' is not assignable to type 'number'.
Shouldn't if (val)
guard against undefined
? It works if I change it to log(val ?? 0)
.
Also, I'm surprised log(val ?? 0)
works. val
could be a truthy value that's not a number, but log()
expects a number. Why doesn't this throw an error?
Upvotes: 2
Views: 297
Reputation: 8380
The problem is well known. You may get some insight what's really happening inside the type checker from this comment:
The core problem is that the narrowed type of fooAnchor is not really speakable. Its unnarrowed type is Partial<FooAnchorMap>[keyof TMap], which isn't a union that we can remove undefined and null from to produce some other type that would be provably-assignable to HTMLElement.
There is work in progress to resolve it. But as of now you're left only with workarounds.
function fn<T extends typeof Base>(
instance: Partial<InstanceType<T>>,
key: keyof InstanceType<T>,
) {
const val: InstanceType<T>[keyof InstanceType<T>] | undefined = instance[key];
if (val) {
log(val);
}
}
And you'll get the correct error: Type 'InstanceType<T>[string]' is not assignable to type 'number'.
Upvotes: 2
Reputation: 1771
The undefined
bit is a red herring; this is only being flagged because strictNullChecks
is enabled which means unless you declare
function log(arg: number) {
console.log(arg);
}
as
function log(arg: number | undefined) {
console.log(arg);
}
it is going to complain whenever you pass anything in which may resolve to undefined
. Disabling strictNullChecks
will eliminate that error (though present others with the above code); alternatively guaranteeing that undefined
is handled before being passed in (e.g. ?? 0
) will also work.
Also, I'm surprised log(val ?? 0) works. val could be a truthy value that's not a number, but log() expects a number. Why doesn't this throw an error?
This should error if val ?? 0
doesn't resolve to a number and log()
expects a number, i.e. in the scenario you described where a truthy non-number is passed in. This fails correctly for me in the playground, do you have an example of this not working?
Upvotes: 0