是否可以定义一个比此类型更安全的函数?
public addBusinessRule(targetProperty: string,
dependentProperties: string[],
callback: (dep0: any, dep1: any, ...)): void {
// some logic...
callback(..dependentProperties)
};
我的目标是对最后2个参数进行类型检查。所以如果我传递这样的内容:
this.addBusinessRule('mortage',
['purchasePrice', 'investiture', 'ownFunds'],
(purchase: number, investiture: number, ownFunds: number) => {
// some calculations
});
任何人都知道我如何从第二个参数定义字符串数组的大小,该参数具有要匹配从回调函数接受的参数数量。
我能以某种方式使用泛型解决此问题,还是可能对此没有解决方案。
如果有人知道更好的更确切的问题标题,请请求编辑!
答案 0 :(得分:2)
您可以使用映射的元组将属性的元组转换为属性类型的元组,然后将其用作回调的参数。这将确保回调最多可以具有与dependentProperties
中的项目相同数量的参数。不会强制您指定所有参数(这是打字稿定义函数的类型兼容性的方式。)
type Data = {
mortage: {
purchasePrice: number,
investiture: number,
ownFunds: number,
otherProp: string
}
}
type MapTuple<T, K extends keyof T, NK extends Array<keyof T[K]>> = {
[P in keyof NK]: NK[P] extends keyof T[K] ? T[K][NK[P]] : never
}
class Test {
public addBusinessRule<K extends keyof Data, NK extends Array<keyof Data[K]>>(targetProperty: K,
dependentProperties: NK | [], // Get the compiler to infer tuple types
callback: (...a: MapTuple<Data, K, NK>) => void): void {
// some logic...
//callback(..dependentProperties)
};
public m() {
this.addBusinessRule('mortage',
['purchasePrice', 'investiture', 'ownFunds', 'otherProp'],
(purchase, investiture, ownFunds, op) => { // param types infered based on Data typr
});
}
}
魔术发生在MapTuple
类型中。该类型使用mapped types(从3.1开始,它也支持元组和数组,请参见PR)。此类型采用一个元组NK
,它是T[K]
的键的元组,并在T[K]
中查找每个属性的类型(这涉及条件类型,因为打字稿无法计算尽管可以保证NK[P]
是T[K]
的键)
如果您只想检查参数的数量而不是参数的类型(尽管我认为这对API使用者来说是更糟糕的体验),则可以执行以下操作:
type MapTuple<NK extends Array<any>> = {
[P in keyof NK]: any
}
class Test {
public addBusinessRule<NK extends Array<string>>(targetProperty: string,
dependentProperties: NK | [], // Get the compiler to infer tuple types
callback: (...a: MapTuple<NK>) => void): void {
// some logic...
//callback(..dependentProperties)
};
public m() {
this.addBusinessRule('mortage',
['purchasePrice', 'investiture', 'ownFunds', 'otherProp'],
(purchase, investiture, ownFunds, op) => { // all of type any
});
}
}
答案 1 :(得分:1)
一个简单的示例,仅适用于字符串型参数?
export const addBusinessRule = <T extends any[]>(targetProperty: string, dependentProperties: T, callback: (...a: T[]) => void) => {
// some logic...
callback(...dependentProperties)
}
addBusinessRule('asd', ['sdf', 'sdf', 'sdf'], (first, second, third) => {
console.log('ABC')
})
它为每个参数提供类型。
如果我们要使用不正确的回调,则TS将引发错误。
const callback = (a: number, b: string, c: boolean) => {
// ...
}
addBusinessRule('asd', ['sdf', 'sdf', 'sdf'], callback)
TS2345: Argument of type '(a: number, b: string, c: boolean) => void' is not assignable to parameter of type '(...a: string[][]) => void'. Types of parameters 'a' and 'a' are incompatible. Type 'string[]' is not assignable to type 'number'.