强类型调度器函数



我有一个接受函数记录的createDispatcher函数
它将返回一个dispatch函数,该函数期望一条记录的关键字与之前提供给createDispatcher的记录中的关键字相对应
有点难以解释,但看看下面的例子,我认为它应该会变得显而易见。

const funcs = {
upCase: (s: string) => s.toUpperCase(),
double: (n: number) => 2*n,
}
const dispatch = createDispatcher(funcs)  // TBD
dispatch({upCase: "test"})             // OK: TEST
dispatch({double: 42})                 // OK: 84
dispatch({double: "test"})             // should be compile error
dispatch({foo: 0})                     // should be compile error
dispatch({upCase: "test", double: 42}) // should be compile error, exactly one key expected
dispatch({})                           // should be compile error, exactly one key expected

以下是我当前对createDispatcher的实现。

function createDispatcher(funcRecord: Record<string, (input: any) => any>) {
function dispatch(inputRecord: Record<string, any>) {
for (const i in inputRecord) {
const func = funcRecord[i]
if (func !== undefined)
return func(inputRecord[i])
}
}
return dispatch
}

它有效,但类型太弱
上面的所有示例都进行了类型检查,而我只希望允许使用1和2
有人能帮忙吗?

您可以从原始func记录开始创建并集。

您可以使用映射类型来遍历func记录中的所有键。对于每个键,我们将创建一个包含该键的对象类型。然后,我们可以使用索引运算符(keyof T(创建一个包含所有这些对象类型的并集。

现在,由于联合的工作方式,您可以指定联合的任何组成部分的键,而不会遇到过多的属性检查,我们需要将func记录中的所有属性添加到每个对象类型中,作为可选的undefined类型,以确保这些属性不会被分配。你可以在这里阅读更多关于这个问题和解决方案的信息,这与我在这里使用的类似:


type InputRecord<T extends Record<string, (input: any) => any>> = {
[P in keyof T]: 
// create an object type with the current key, typed as the first parameter of the function
Record<P, Parameters<T[P]>[0]> 
// Ensure no other fields are possible
& Partial<Record<Exclude<keyof T, P>, undefined>>
}[keyof T]
function createDispatcher<T extends Record<string, (input: any) => any>>(funcRecord: T) {
function dispatch(inputRecord: InputRecord<T>) {
for (const i in inputRecord) {
const func = funcRecord[i]
if (func !== undefined)
return func(inputRecord[i])
}
}
return dispatch
}

游乐场链接

最新更新