打字稿强制该字符串值是对象值之一

Typescript enforce that string value is one of the object values

我有这个常量声明:

export const Actions = {
    VIEW: 'view',
    EDIT: 'edit',
};

现在假设我有如下函数:

// how to ensure action variable below is string of value either view or edit
function insertAction(action: string): void {
  console.log('trust me i inserted the action');
}

我的目标是让动作参数只有值 view | edit 并动态地理解这一点,所以请不要建议使用联合解决方案,因为我已经知道它不适合我的目的。

我试过像下面这样的签名

function insertAction(action: typeof Actions[keyof typeof Actions]

但它不起作用。

我仍然可以调用函数 insertAction('whatever') 并且 ts 编译不会使 linter 失败。

在我的 package.json 中,我使用带有 PHPStorm 编辑器和 nextjs 的 typescript 版本 4.4.2

    "typescript": "^4.4.2"

您当前的解决方案:

function insertAction(action: typeof Actions[keyof typeof Actions])

应该可以工作,只要您使用 as const modifier:

声明 Actions 对象
export const Actions = {
    VIEW: 'view',
    EDIT: 'edit',
} as const; // <-- note the assertion here.

这是有效的,因为默认情况下,当您声明一个没有显式类型的对象时,例如:

export const Actions = {
    VIEW: 'view',
    EDIT: 'edit',
}

TypeScript 可以看到 变量 是常量,不能重新分配。然而,由于它被分配了一个具有潜在 可变值 的对象,TypeScript 将为该对象推断类型:

{
  VIEW: string;
  EDIT: string;
}

您想要的值类型不是 string,而是 "view""edit" 的确切 文字字符串类型 .使用 as const 修饰符会通知 TypeScript 对象 的值不会发生变化 ,因此它将为这些值推断出更严格的文字字符串类型。

然后,由于值类型分别是确切的字符串 "view""edit",使用 typeof Actions[keyof typeof Actions] 将产生联合类型 "view" | "edit",这正是需要的你的参数类型。

为什么不使用枚举和赋值 action:EAction

应该是这样的:

export enum EActions {
    VIEW = 'view',
    EDIT = 'edit',
}

你的函数

function insertAction(action: EAction): void {
  console.log('trust me i inserted the action');
}

会告诉你输入错误:

insertAction('whatever'); // will show you error

“whatever”类型的参数不能分配给 'EAction' 类型的参数。

使用您的 EActions:

insertAction(EAction.VIEW);

我觉得读起来会更容易。

示例: JS Playground