提问人:michaelmcandrew 提问时间:11/15/2023 更新时间:11/15/2023 访问量:22
创建一个函数,该函数返回一个函数,该函数的行为方式与传入的函数相同
create a function that returns a function that behaves in the same way as the passed in function
问:
我正在尝试创建一个函数,该函数接受一个函数作为参数,并返回一个函数,该函数的行为方式与传入函数(作为一些更复杂的业务逻辑的核心)相同。
// a function that returns a function that behaves
// in the same way as the passed in function.
export function create<T extends Function>(func: T): T {
function run(...args: any[]) {
// Later I plan on doing some stuff here...
return func(...args);
// ...and here
}
return run;
}
const source = (n:number) => n.toString();
const created = create(source);
上面的代码有效,我在 () 上获得了正确的类型注释和完成,但打字稿抱怨created()
const created: (n: number) => string
键入 '(...args: any[]) => any' 不可分配给类型 'T'。 '(...args: any[]) => any' 可分配给类型为 'T' 的约束,但 'T' 可以使用约束 'Function' 的不同子类型进行实例化。
这个消息对我来说有点难以理解。你能帮我理解它并提出一些解决这个问题的方法吗?谢谢!!
答:
呼叫签名的问题,例如
function create<T extends Function>(func: T): T { /* ✂ ⋯ ✂ */ }
是它声称无论如何都返回与输入类型完全相同的值。JavaScript 中的函数是第一类对象,也可以像任何其他对象一样具有属性。所以你可以这样做:func
const source = (n: number) => n.toString();
source.prop = "hello";
/* const source: {
(n: number): string;
prop: string;
} */
下面是一个具有字符串值属性的函数。但是,您的实现不会尝试确保将 的每个属性都复制到输出中。因此,编译器会警告您,虽然返回的函数肯定是 ,但它可能不是 .如果忽略该错误,则可能会发生以下问题:source
prop
create()
func
Function
T
const created = create(source);
console.log(created(123)) // "123", this is good
try {
console.log(created.prop.toUpperCase()) // no compiler error, but
} catch (e) {
console.log(e) // 💥 RUNTIME ERROR: created.prop is undefined
}
编译器很乐意允许您访问,因为据说返回的内容与 .并且您收到运行时错误。哎呀。create.prop
create(source)
create
做你正在做的事情的传统方法是明确地只关心输入的调用签名,而不是整个输入类型:也就是说,你希望函数在参数类型和返回类型列表中是泛型的:A
R
function create<A extends any[], R>(func: (...args: A) => R): (...args: A) => R {
function run(...args: A) {
return func(...args);
}
return run; // okay
}
现在编译时没有错误。您仍然可以将具有额外属性的函数传递到 ,但现在输出值不会假装具有此类额外属性,因此您会收到编译器错误,这将帮助您避免运行时错误:create()
const source = (n: number) => n.toString();
source.prop = "hello";
const created = create(source);
console.log(created(123)) // "123" // this is good
created.prop; // compiler error
// ~~~~
// Property 'prop' does not exist on type '(n: number) => string'
评论