Home > Blockchain >  Mapping array parameter type to array return type?
Mapping array parameter type to array return type?

Time:05-08

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,
]);

Playground

  • Related