TypeScript 泛型 - 期望类型参数是枚举,并引用它的键

TypeScript generics - expect type argument to be enum, and refer to its keys

我正在尝试在 React 和 Typecript 中创建一个可重用的多步向导组件。该向导将需要通过反应上下文对象将某些值传递给它。该上下文对象的值必须遵循一般模式:

export interface WizardContextValues {
  currentStep: number;
  setStep: (stepState: number) => void;
  completedSteps: { [key: string]: boolean };
  setCompletedSteps: (state: { [key: string]: boolean }) => void;
  disabledSteps: { [key: string]: boolean };
}

您可以看到 completedStepsdisabledSteps,我期待一个对象。但我想多限制一点。假设对于一个特定的向导,我有一个步骤枚举:

export enum UploadWizardSteps {
  UPLOAD_FILE,
  GIVE_DETAILS,
  CONFIRMATION
}

我实际上想让 WizardContextValues 通用,这样它就可以将步骤枚举作为参数。像这样:

export interface WizardContextValues<Steps> {
  currentStep: number;
  setStep: (stepState: number) => void;
  completedSteps: { [key in Steps]: boolean };
  setCompletedSteps: (state: { [key in Steps]: boolean }) => void;
  disabledSteps: { [key in Steps]: boolean };
}

type UploadWizardContext = WizardContextValues<UploadWizardSteps>

我在尝试使用 key in Steps 时遇到错误,显示 Type 'Steps' is not assignable to type 'string | number | symbol'. Type 'Steps' is not assignable to type 'symbol'

这种是有道理的,因为在定义泛型 interface WizardContextValues<Steps> 时,typescript 不知道 Steps 是一个枚举并且可以使用 key in 运算符引用它的键.

typescript playground showing the issue

如何创建此泛型类型,使 UploadWizardContext 的某些属性必须是其键值为 UploadWizardSteps 的对象?

按照目前的编写方式,TypeScript 在 WizardContextValues 中使用时无法知道有关 Steps 的任何信息。您大概可以将其中的任何内容作为类型传递,包括不能用作键的内容。

您可以通过使用 extends.

限制可用于 Steps 的类型来解决此问题

默认情况下,TypeScript 枚举使用 number 值,但您可以使用更宽的 string | number | symbol 类型来完全反映可用于对象属性的内容:

export enum UploadWizardSteps {
  UPLOAD_FILE,
  GIVE_DETAILS,
  CONFIRMATION
}

export interface WizardContextValues<Steps extends string | number | symbol> {
  currentStep: number;
  setStep: (stepState: number) => void;
  completedSteps: { [key in Steps]: boolean };
  setCompletedSteps: (state: { [key in Steps]: boolean }) => void;
  disabledSteps: { [key in Steps]: boolean };
}

type UploadWizardContext = WizardContextValues<UploadWizardSteps>

TypeScript playground