I'm trying to type an interface (or type) with the following logic:
interface MyArgs<Name, Id> {
items: {
[Name]: string,
[Id]: string
}[];
idKey: string;
nameKey: string;
}
In more detail:
I'm getting an array of items of an unknown type/interface (it's dynamic, they can be anything). While I could just type them as any[], I'd like to know if it's possible to be a bit more specific about their type, and pass Typescript the information that I do have:
each item will be having an id property (e.g: guid, id, uuid) and a name property (e.g: name, label, title). The exact idKey and nameKey are provided as arguments (idKey, nameKey).
I want to declare the values provided in idKey and nameKey as valid keys for items records (e.g: { [idKey]: string; [nameKey]: string }(
What I tried above doesn't work. I also tried this:
interface MyArgs<Name, Id> {
items: { <Name>: string; <Id> : string }[]
idKey: string
nameKey: string
}
which is, too, invalid.
How can I achieve this?
Note: if the above would be possible without having to type the values twice (once inside <> and once in the values of idKey and nameKey, that would be even more awesome).
CodePudding user response:
Intersect mapped types (or rather, Records) to create the correct object type:
interface MyArgs<Name extends string, Id extends string> {
items: (
{ [_ in Name]: string; } &
{ [_ in Id]: string; }
)[];
idKey: string;
nameKey: string;
}
If you need to, you can also constrain Name and Id to more specific keys:
interface MyArgs<Name extends "name" | "label" | "title", Id extends "guid" | "id" | "uuid"> {
You could also use Records to simplify it further:
items: (
Record<Name, string> & Record<Id, string>
)[];
Or even just:
items: Record<Id | Name, string>[];
