I have an enum to describe "fields", and a mapping of each field to a type:
enum Field {
Id,
Position,
Name,
Enabled,
}
interface FieldTypes extends Record<Field, any> {
[Field.Id]: number;
[Field.Position]: number;
[Field.Name]: string;
[Field.Enabled]: boolean;
}
I wrote a function to extract a given field from some data
(which I've defined here as unknown
type because it's not important for this question):
declare function getField<F extends Field>(
data: unknown,
field: F
): FieldTypes[F];
const position: number = getField({}, Field.Position);
const name: string = getField({}, Field.Name);
This compiles without error. getField
indeed returns a number
for position
and a string
for name
.
Now I want to write a getFields
function that extracts multiple fields from data
in order, but I'm struggling to define it. Here's how I expect it to work:
const fields: [boolean, number, number] = getFields({}, [
Field.Enabled,
Field.Id,
Field.Position,
]);
So how do I define this function? This is what I tried but it doesn't return the correct type:
declare function getFields<F extends Field>(
data: unknown,
fields: F[]
): FieldTypes[F][];
CodePudding user response:
This should work for you:
enum Field {
Id,
Position,
Name,
Enabled,
}
interface FieldTypes extends Record<Field, any> {
[Field.Id]: number;
[Field.Position]: number;
[Field.Name]: string;
[Field.Enabled]: boolean;
}
First we create another type
which takes an tuple of Field
and returns an tuple with the corresponding types.
type MultipleFieldTypes<T extends readonly Field[]> = {
[K in keyof T]: T[K] extends keyof FieldTypes ? FieldTypes[T[K]] : never
}
Then we modify the function getFields
to accept a tuple of Field
as the generic type F
. As the return type we pass F
to MultipleFieldTypes
.
declare function getFields<F extends Field[]>(
data: unknown,
fields: [...F]
): MultipleFieldTypes<F>;
Now we have the correct return type:
const fields: [boolean, number, number] = getFields({}, [
Field.Enabled,
Field.Id,
Field.Position,
]);