TypeScript 中布尔值作为对象键类型

Ili*_*hev 5 javascript pattern-matching typescript

when我想在 Typescript 中实现一个类似于 Kotlin 中的运算符的类似 switch 的功能。

用法示例:

const a = 30;
const b = 10;

const result = when(
   {[a < b]: 'somethin'},
   {[a > b]: 'somethin else'},
   {[a >= b]: 'somethin else 2'},
)

>> result == 'something else'
Run Code Online (Sandbox Code Playgroud)

它返回第一个条件评估为 true 的情况的值。

我尝试做这样的事情:

type Case<T> = { [key: boolean]: T };

function when<T>(...cases: Case<T>[]) {
  const index = cases.findIndex(c => c.hasOwnProperty(true));
  return index >= 0 ? cases[index][true] : undefined;
}
Run Code Online (Sandbox Code Playgroud)

但 TS 编译器抱怨An index signature parameter type must be either 'string' or 'number'.ts(1023).

另外,当我尝试做这样的事情时:

const foo = {[a > b]: 'something'};
Run Code Online (Sandbox Code Playgroud)

TS 再次出错A computed property name must be of type 'string', 'number', 'symbol', or 'any'.ts(2464)

这可以在纯 JS 中轻松完成,因为计算属性中的布尔结果会自动强制(转换为)字符串。

我找不到任何在线执行此操作的方法,因此决定这样做:

function when<T>(...cases: [boolean, T][]) {
  const index = cases.findIndex(([condition, _]) => condition);
  return index >= 0 ? cases[index][1] : undefined;
}

when(
   [a < b, 'somethin'],
   [a > b, 'somethin else'],
   [a >= b, 'somethin else 2'],
)
Run Code Online (Sandbox Code Playgroud)

这很好,但我发现第一个示例的语法看起来更令人愉悦。

我是否遗漏了什么或者这是当前规范的限制?

sau*_*edo 0

TypeScript 具有强类型,你不应该期望这样的强制。JavaScript 中的对象键必须是字符串或数字。这就是为什么 TypeScript 要求你不要使用布尔值。您可以尝试以下解决方案:

type Case<T> = { [key in "true" | "false"]: T };
Run Code Online (Sandbox Code Playgroud)

但是,您需要注意不能有两个相同的密钥:请参阅下面的示例:

let sampleObject = {
    "true": 'something',
    "false": 'something else',
    "false": 'something else 2'
}

console.log(sampleObject);
// will print { true: "something", false: "something else 2" }
// note that the second value is not available because
// you cannot have 2 "false" keys
```

Run Code Online (Sandbox Code Playgroud)

  • 您建议的类型适用于您的示例,但它不会让我拥有布尔计算属性名称,而这正是我最终想要的。由于 TS 是 JS 的“超集”,我希望能够在 TS 中执行类似“const a = {[true]: 'something'}”的操作,这是有效的 JS。 (4认同)