将数组参数类型映射到数组返回类型?

Xåp*_* - 2 typescript

我有一个枚举来描述“字段”,以及每个字段到类型的映射:

enum Field {
  Id,
  Position,
  Name,
  Enabled,
}

interface FieldTypes extends Record<Field, any> {
  [Field.Id]: number;
  [Field.Position]: number;
  [Field.Name]: string;
  [Field.Enabled]: boolean;
}
Run Code Online (Sandbox Code Playgroud)

我编写了一个函数来从某些字段中提取给定的字段data(我在这里将其定义为unknown类型,因为它对于这个问题并不重要):

declare function getField<F extends Field>(
  data: unknown,
  field: F
): FieldTypes[F];

const position: number = getField({}, Field.Position);
const name: string = getField({}, Field.Name);
Run Code Online (Sandbox Code Playgroud)

这编译没有错误。getField确实返回一个numberforposition和一个stringfor name。

现在我想编写一个按顺序getFields提取多个字段的函数data,但我很难定义它。我期望它的工作方式如下:

const fields: [boolean, number, number] = getFields({}, [
  Field.Enabled,
  Field.Id,
  Field.Position,
]);
Run Code Online (Sandbox Code Playgroud)

那么如何定义这个函数呢?这是我尝试过的,但它没有返回正确的类型:

declare function getFields<F extends Field>(
  data: unknown,
  fields: F[]
): FieldTypes[F][];
Run Code Online (Sandbox Code Playgroud)

Tob*_* S. 6

这应该适合你:

enum Field {
  Id,
  Position,
  Name,
  Enabled,
}

interface FieldTypes extends Record<Field, any> {
  [Field.Id]: number;
  [Field.Position]: number;
  [Field.Name]: string;
  [Field.Enabled]: boolean;
}
Run Code Online (Sandbox Code Playgroud)

首先,我们创建另一个type,它接受一个元组Field并返回一个具有相应类型的元组。

type MultipleFieldTypes<T extends readonly Field[]> = {
    [K in keyof T]: T[K] extends keyof FieldTypes ? FieldTypes[T[K]] : never
}
Run Code Online (Sandbox Code Playgroud)

然后我们修改函数getFields以接受元组Field作为泛型类型F。作为返回类型,我们传递F给MultipleFieldTypes.

declare function getFields<F extends Field[]>(
  data: unknown,
  fields: [...F]
): MultipleFieldTypes<F>;
Run Code Online (Sandbox Code Playgroud)

现在我们有了正确的返回类型:

const fields: [boolean, number, number] = getFields({}, [
  Field.Enabled,
  Field.Id,
  Field.Position,
]);
Run Code Online (Sandbox Code Playgroud)

操场

  • 谢谢@TobiasS。为了澄清。另请参阅以下答案链接,您可以使用 [...T] 进行元组推断。这样 getFields 得到 `&lt;F extends Field[]&gt;` 并且 fields 变成 `fields: [...F]` /sf/answers/4686757911/ (3认同)
  • 这是一种“解决方法”,因此调用者不必使用“as const”,并且打字稿不会将其识别为“数组”,而是将其识别为元组。请参阅此处/sf/answers/4059438421/ (2认同)