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'
在对象参数中 - 键必须涵盖所有可能的类型 value
(1
和 'foo'
在上面的例子中) - 否则 TS 应该抛出错误,缺少特定的 属性。
在对象参数中 - 值必须是函数 - 否则 TS 应该抛出一个错误,指出值不可分配给函数
“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 键入 any
或 unknown
.
(我知道条件类型和推断,但这些知识在这种情况下对我没有帮助...)
如何输入这个匹配函数?
干杯!
尝试重载你的函数:
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
我知道,我用过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
如果你想了解更多关于参数的函数推断,你可以查看我的 article
我正在尝试实现 match from Rust
的简单版本它应该像这样工作:
const value = Math.random() > 0.5 ? 1 : 'foo'
const result = match(value, {
1: () => 100,
foo: () => 'F'
})
result // 100 | 'F'
在对象参数中 - 键必须涵盖所有可能的类型
value
(1
和'foo'
在上面的例子中) - 否则 TS 应该抛出错误,缺少特定的 属性。在对象参数中 - 值必须是函数 - 否则 TS 应该抛出一个错误,指出值不可分配给函数
“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 键入 any
或 unknown
.
(我知道条件类型和推断,但这些知识在这种情况下对我没有帮助...)
如何输入这个匹配函数?
干杯!
尝试重载你的函数:
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
我知道,我用过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
如果你想了解更多关于参数的函数推断,你可以查看我的 article