Home > database >  Generic is generalised to a string in TypeScript
Generic is generalised to a string in TypeScript

Time:06-11

I have a generic function, which can be simplified to the example below:

type Delegate<Key extends "firstKey" | "secondKey"> = {
  key: Key;
  deleteMany: (where: { where: { [n in Key]: string } }) => Promise<unknown>;
};

const removeDuplicatesGeneric = <Key extends "firstKey" | "secondKey">(
  delegate: Delegate<Key>
) => {
  delegate.deleteMany({ where: { [delegate.key]: 'key' } });
};

As key is of the type Key, I expect it to not cause issues when passing to where. TypeScript shows me an error though:

Type '{ [x: string]: string; }' is not assignable to type '{ [n in Key]: string; }'.

Any ideas why [delegate.key] is interpreted as x: string instead of x: Key?

CodePudding user response:

This behavior is by design. Because string type is much wider than "firstKey" | "secondKey" you are getting an error.

In this case, it is ok to use type assertion:

type Delegate<Key extends "firstKey" | "secondKey"> = {
    key: Key;
    deleteMany: (arg: { where: Record<Key, string> }) => Promise<unknown>;
};

const record = <
    Key extends PropertyKey,
    Value
>(key: Key, value: Value) =>
    ({ [key]: value }) as Record<Key, Value>

const removeDuplicatesGeneric = <Key extends "firstKey" | "secondKey">(
    delegate: Delegate<Key>
) => {
    delegate.deleteMany({ where: record(delegate.key, 'key') });
};

Playground

  • Related