TypeScript 中的简单 rust "match" 实现。如何键入函数?

Simple rust "match" implementation in TypeScript. How to type the function?

我正在尝试实现 match from Rust

的简单版本

它应该像这样工作:

const value = Math.random() > 0.5 ? 1 : 'foo'
 
const result = match(value, {
  1: () => 100,
  foo: () => 'F'
})
  
result // 100 | 'F'
  1. 在对象参数中 - 键必须涵盖所有可能的类型 value1'foo' 在上面的例子中) - 否则 TS 应该抛出错误,缺少特定的 属性。

  2. 在对象参数中 - 值必须是函数 - 否则 TS 应该抛出一个错误,指出值不可分配给函数

  3. “default case”不重要,稍后我会尝试实现

我得到的最佳方法:

export function match<
  Case extends string | number,
  Options extends Record<Case, any>
>(case: Case, options: Options): ReturnType<Options[Case]> {
  return options[case]()
}

这种使用 any 关键字的解决方法有一个主要问题 - 代码可能会在运行时中断。当我尝试以某种方式键入此 any - 我总是以 return 键入 anyunknown.

(我知道条件类型和推断,但这些知识在这种情况下对我没有帮助...)

如何输入这个匹配函数?

干杯!

尝试重载你的函数:


function match<
  Key extends PropertyKey,
  ReturnValue extends string | number,
  Branch extends () => ReturnValue,
  Options extends Record<Key, Branch>,
  Variant extends keyof Options
>(options: Options, variant: Variant): ReturnType<Options[Variant]>
function match(options: Record<PropertyKey, () => unknown>,variant: PropertyKey, ) {
  return options[variant]()
}


const result1 = match({
  1: () => 100,
  foo: () => 'F'
}, 1) // 100

const result2 = match({
  1: () => 100,
  foo: () => 'F'
}, 'foo') // snumber


Playground

我知道,我用过unknown,但我没有在我的重载签名中使用它。如果将鼠标悬停在 match 上,您将看到推断出每个对象 key/value。

为了推断文字类型,您应该使用文字对象作为第一个参数或使其不可变。

我认为让它不可变是一种可行的方法,因为我认为它将在几个函数中使用:


function match<
  Key extends PropertyKey,
  ReturnValue,
  Branch extends () => ReturnValue,
  Options extends Record<Key, Branch>,
  Variant extends keyof Options
>(options: Options, variant: Variant): ReturnType<Options[Variant]>
function match(options: Record<PropertyKey, () => unknown>, variant: PropertyKey,) {
  return options[variant]()
}

const strategy = {
  1: () => 100 as 100,
  foo: () => 'F' as 'F'
} as const

const result1 = match(strategy, 1) // 100

const result2 = match(strategy, 'foo') // F

Playground

如果你想了解更多关于参数的函数推断,你可以查看我的 article