【发布时间】:2021-03-01 07:56:30
【问题描述】:
这个问题最重要的是,激发我的好奇心,加深我对使用泛型时 typescript 类型推断的内部工作原理的理解。
问题
我想创建一个高阶函数,为接收的函数添加额外的参数:
type WithConfirmProps = {
action: Function;
text: string;
}
type CustomFunction<P> = (arg: P) => void
export function withConfirm<P>(innerFunction: CustomFunction<P>) {
const wrappedFunction = ({ action, text, ...rest }: P & WithConfirmProps) => {
// ...
// code that uses action and text...
rest; // inferred type is 'Pick<P & WithConfirmProps, Exclude<keyof P, "action" | "text">>'
// but I expected it to be simply 'P',
// or at least that the 'Exclude' would be applied to 'WithConfirmProps', not to 'P'
return innerFunction(rest);
// error here ˆˆˆˆ is:
// Argument of type 'Pick<P & WithConfirmProps, Exclude<keyof P, "action" | "text">>' is not assignable to parameter of type 'P'.
// 'P' could be instantiated with an arbitrary type which could be unrelated to 'Pick<P & WithConfirmProps, Exclude<keyof P, "action" | "text">>'.(2345)
};
return wrappedFunction;
}
我发现错误信息有些难以理解,但经过一番思考,我对问题的解释是:
P类型本身可以具有action和text属性,这就是为什么rest不能被推断为P的原因
我的解决方案
根据上面的解释,我试图向编译器传达通用P 实际上没有action 和text 属性。
下面的sn-p显示没有编译错误:
export function withConfirm<P>(innerFunction: CustomFunction<Pick<P, Exclude<keyof P, 'action' | 'text'>>>) {
const wrappedFunction = ({ action, text, ...rest }: P & WithConfirmProps) => {
// ...
// code that uses action and text...
rest; // type is Pick<P & WithConfirmProps, Exclude<keyof P, "action" | "text">>
return innerFunction(rest); // 'rest' has exactly the same inferred type,
// but now it does not error ????♂️
};
return wrappedFunction;
}
你可以在这个typescript playground中重现这个问题
- 问题 1:我对错误的解释是否正确?
- 问题 2:有没有更好的方法来键入函数?
【问题讨论】:
标签: typescript typescript-generics