Why the following example fails to compile?
function mapObjectValues<I, O, K extends keyof any>(obj: Record<K, I>, map: (value: I, key: K) => O): Record<K, O>
function mapObjectValues<K extends keyof any, I extends Record<K, any>, O extends Record<K, any>>(obj: I, map: (value: I[K], key: K) => O[K]): O
function mapObjectValues<I, O>(obj: Record<keyof any, I>, map: (value: I, key: keyof any) => O): Record<keyof any, O>
function mapObjectValues<I, O>(_obj: Record<keyof any, I>, _map: (value: I, key: keyof any) => O): Record<keyof any, O> {
throw "not relevant"
}
function checker(_input: Record<string, string>) { }
// compiles
checker(mapObjectValues({
foo: "bar"
}, (_, k) => k))
// compiles
checker(mapObjectValues({
["foo"]: "bar"
}, (_, k) => k))
// fails with:
//
// Argument of type 'Record<string | number, string | number>' is not assignable to parameter of type 'Record<string, string>'.
// 'string' index signatures are incompatible.
// Type 'string | number' is not assignable to type 'string'.
// Type 'number' is not assignable to type 'string'.
checker(mapObjectValues({
[{
foo: "foo"
}.foo]: "bar"
}, (_, k) => k))
// compiles
checker(mapObjectValues({
[({
foo: "foo"
} as const).foo]: "bar"
}, (_, k) => k))
Is it a current limitation of type inference in TypeScript?
This is due to keyof
of indexed types returning number | string
.
type foo = keyof { [x: string]: string; }
// ^? type foo = number | string
Per this issue on the Typescript GH, it works as intended.