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>[];