If I have a dictionary D
with the keys constrained to type string
, generics that are of type keyof D
seem to still be inferred as string | number | symbol
.
A basic ts playground example here.
type Foo = {
[key: string]: any
}
const bar = (blah: string) => {
return blah;
}
const foo = <T extends Foo, N extends keyof T>(dict: T, key: N) => {
bar(key); // Err: Type 'number' is not assignable to type 'string'.
console.log(dict);
}
In the example above, how can I constrain N
so that it:
- can be passed into
bar
and - must be one of the keys of the dictionary
T
?
CodePudding user response:
The problem is that:
const sym = Symbol('mysym')
const test = { abc: 123, [sym]: 456 }
const foo: Foo = test // fine
So the type:
{ abc: number, [sym]: number }
Actually extends the type:
{ [key: string]: any }
If you want N
to constrained to only strings, then you can just intersect that requirement with the constraint for N
.
const foo = <
T extends Foo,
N extends keyof T & string
>(dict: T, key: N) => {
return bar(key);
}
foo({ a: 123 }, 'a') // fine
foo({ a: 123 }, 'b') // error