Home > Mobile >  Typescript generic that extends the `keyof` a dictionary with keys constrained to `string` is not co
Typescript generic that extends the `keyof` a dictionary with keys constrained to `string` is not co

Time:11-30

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

See Playground

  • Related