-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Description
TypeScript Version: 2.3.2
Code
function ff<T extends {[k: string]: number | boolean}, K extends keyof T>(x: T, k: K, v: T[K]): void {
}
let val = {a: 5}
ff(val, 'a', 9)
// PROBLEM: argument of type '9' is not assignable to parameter of type '5'
ff({a: 5}, 'a', 9)
function gg<T extends {[k: string]: number | string}, K extends keyof T>(x: T, k: K, v: T[K]): void {
}
gg({a: 5}, 'a', 9)
gg(val, 'a', 9)Expected behavior:
The type inferencer makes no difference between any of those four calls.
Actual behavior:
The type inferencer seems to treat the generic T differently based on whether there's a literal in the union of allowed types and based on whether the argument is passed from a variable or directly. The first ff() call infers a as the literal 5 while the second one infers it as number.
This happens when you have a literal in the union. I suppose boolean is equivalent to true | false? You can trigger the same behavior when replacing boolean with some string literal. However, if you use number | string like in gg the type of a becomes number in both cases.
What's unexpected here is that I've told the compiler about my allowed types: number | boolean. No other type (not even a more specific one) should be inferred unless I explicitly list it (e.g.: number | 5). Especially, some unrelated literal (boolean) shouldn't change the inference behavior of number.