我想用函数修饰符的链修改数据,但要在打字脚本中正确键入.这个是可能的吗?

const addA = (data: {}) => {
  return {
    ...data,
    a: "test"
  }
}

const addB = (data: {}) => {
  return {
    ...data,
    b: "test"
  }
}

const updateA = (data: {a:string}) => {
  return {
    ...data,
    a: data.a + " test"
  }
}

const func = <T extends ((data: Record<string, any>) => Record<string, any>)[]>(modifiers: T): unknown => {
  return modifiers.reduce((acc, modifier) => {
    return modifier(acc)
  }, {})
}

console.log(func([addA])) // Pass, Should pass.
console.log(func([addA, addB])) // Pass, Should pass.
console.log(func([addA, addB, updateA])) // Error, Should pass.
console.log(func([updateA])) // Error, Should error. Unexpected runtime undefined value.

Playground

推荐答案

注意:您的函数总是在输出中散布输入,但您的类型并不实际反映这一点.您可以使用泛型来说明这一点,但这会使下面的解决方案更加困难.只要遵循这样的约定,即函数产生的东西至少是得到的东西,下面的解决方案就会起作用.

可以使用类型参数将函数数组推断为元组.然后,您可以使用递归条件类型来构建函数的实际类型的元组.然后将类型参数与此验证类型相交.如果一切正常,判断基本上是NOP,否则会从交叉口得到错误:

type FunctionArray = Array<(p: any) => any>;
type ValidateChain<T extends FunctionArray , Input = {}, Result extends any[] = []> = 
  T extends [(data: Input) => infer R, ...infer Tail extends FunctionArray] ? ValidateChain<Tail, Input & R, [...Result, T[0]]>:
  T extends [(...p: infer P) => infer R, ...infer Tail extends FunctionArray] ? ValidateChain<Tail, Input & R, [...Result, (data: Input) => R]>:
  Result

type MergeAll<T extends FunctionArray , Input = {}> = 
  T extends [(data: any) => infer R, ...infer Tail extends FunctionArray] ? MergeAll<Tail, R & Input>: Input

const func = <T extends [] | FunctionArray>(modifiers: T & ValidateChain<T>): MergeAll<T> => {
  return (modifiers as T).reduce((acc, modifier) => {
    return modifier(acc)
  }, {}) as MergeAll<T> 
}

let r1 = func([addA]) // Pass
let r2 = func([addA, addB]) // Pass
let r3 = func([addA, addB, updateA]) //Pass.
let r4 = func([addA, addB, updateC]) // Fails
let r5 = func([updateA]) // Fails

Playground Link

您可以了解有关条件类型的更多信息

Typescript相关问答推荐

类型脚本不会推断键的值类型

对于使用另一个对象键和值类型的对象使用TS Generics

类型脚本强制泛型类型安全

数组文字中对象的从键开始枚举

与字符串文字模板的结果类型匹配的打字脚本

如何将所有props传递给React中的组件?

为什么在回调函数的参数中不使用类型保护?

参数属性类型定义的REACT-RUTER-DOM中的加载器属性错误

分解对象时出现打字错误

限制返回联合的TS函数的返回类型

与toast.error一起react 中的Async TUNK错误消息

回调函数中的TypeScrip类型保护返回Incorect类型保护(具有其他未定义类型的返回保护类型)

在抽象类属性定义中扩展泛型类型

Typescript,如何在通过属性存在过滤后重新分配类型?

map 未显示控制台未显示任何错误@reaction-google-map/api

如何调整项目数组,但允许权重影响顺序

如何将对象的字符串文字属性用作同一对象中的键类型

如何实现允许扩展泛型函数参数的类型

如何在Vuetify 3中导入TypeScript类型?

const nav: typechecking = useNavigation() 和 const nav = useNavigation() 之间有什么区别?