TypeScript调用签名技术求助:编译与运行结果矛盾
TypeScript调用签名实现问题解析与修复
问题根源分析
第一个场景:运行报错
logFunc is not a function
你定义的LogFunctionWithPrefixCB是一个带属性的函数类型,要求值本身是可调用的函数,同时拥有logPrefix属性。但你返回的ret是普通对象,只是通过类型断言as LogFunctionWithPrefixCB让TS认为它符合类型,但JS运行时里普通对象无法直接作为函数调用,因此触发错误。第二个场景:编译报错
Expected 2 arguments, but got 1
你调用logFunc.call("hello world")时,TS识别的call是标准Function.prototype.call方法,它要求第一个参数是绑定的this,第二个才是函数参数。虽然你的自定义对象上有call方法,但TS并没有将其纳入类型检查,而是沿用标准函数的call签名,因此提示参数数量不足。
正确实现方式
要满足带属性的函数类型,必须创建一个函数对象,再给它添加额外属性,而不是用普通对象模拟。以下是几种可行的写法:
写法一:先创建函数再添加属性
type LogFunctionWithPrefixCB = { logPrefix: string; (stringToLog: string): void; } function makeLogFunctionWithPrefixCB(prefixStr: string): LogFunctionWithPrefixCB { // 定义基础函数 const loggerFunc = function(stringToLog: string) { console.log(`${this.logPrefix}: ${stringToLog}`); }; // 断言为目标类型并添加属性 const logger = loggerFunc as LogFunctionWithPrefixCB; logger.logPrefix = prefixStr; return logger; } // 使用示例 function doSomething(logFunc: LogFunctionWithPrefixCB) { logFunc("hello world"); // 编译、运行均正常 } const logger = makeLogFunctionWithPrefixCB("prefix:"); doSomething(logger);
写法二:用Object.assign合并函数与属性
type LogFunctionWithPrefixCB = { logPrefix: string; (stringToLog: string): void; } function makeLogFunctionWithPrefixCB(prefixStr: string): LogFunctionWithPrefixCB { return Object.assign( function(stringToLog: string) { console.log(`${this.logPrefix}: ${stringToLog}`); }, { logPrefix: prefixStr } ) as LogFunctionWithPrefixCB; }
写法三:箭头函数版本(词法作用域绑定)
如果不想依赖this,可以用箭头函数直接引用自身属性:
type LogFunctionWithPrefixCB = { logPrefix: string; (stringToLog: string): void; } function makeLogFunctionWithPrefixCB(prefixStr: string): LogFunctionWithPrefixCB { const logger = ((stringToLog: string) => { console.log(`${logger.logPrefix}: ${stringToLog}`); }) as LogFunctionWithPrefixCB; logger.logPrefix = prefixStr; return logger; }
以上写法都能让返回值同时满足“可调用”和“拥有logPrefix属性”的要求,编译和运行阶段都不会出现错误。
内容的提问来源于stack exchange,提问作者MichaelMoser
相关产品推荐
相关产品推荐

