TypeScript:如何实现含调用与构造签名的接口?能否创建实例?
在TypeScript中实现含调用签名与构造签名的接口
首先,你定义的接口I要求对象同时具备两种核心能力:
- 直接调用(
(): string):像普通函数一样执行,返回字符串 - 构造调用(
new(): any):用new关键字实例化,返回任意类型的对象
实现方法
在JavaScript中,函数本身既是可调用的,又可以作为构造函数(通过new调用),我们可以利用这一特性来实现该接口,主要有两种实用方式:
1. 直接编写函数表达式(结合类型标注)
我们可以写一个函数,通过new.target判断调用方式,分别返回对应结果,然后将其标注为接口I的类型:
interface I { (): string; new(): any; } const myImplementation: I = function() { // 判断是否通过new关键字调用 if (new.target) { // 构造调用场景:返回任意结构的对象(满足new(): any的要求) return { id: 1, name: "instance" }; } else { // 直接调用场景:返回字符串(满足(): string的要求) return "Hello from direct function call!"; } }; // 验证调用逻辑 console.log(myImplementation()); // 输出: "Hello from direct function call!" const instance = new myImplementation(); // instance为any类型,符合接口要求
2. 结合类与函数包装(适合复杂构造逻辑)
如果你的构造实例需要复杂的初始化逻辑,可以先定义一个类,再用函数包装实现两种调用方式:
interface I { (): string; new(): any; } // 定义构造调用时返回的类 class MyInstance { public createdAt: Date; constructor() { this.createdAt = new Date(); } } const myImplementation: I = function() { if (new.target) { // 构造调用时返回类的实例 return new MyInstance(); } else { // 直接调用时返回字符串 return "Hello from wrapped function!"; } }; // 验证逻辑 console.log(myImplementation()); // 输出: "Hello from wrapped function!" const instance = new myImplementation(); console.log(instance.createdAt); // 输出当前时间
关键注意事项
- 不能直接用类实现该接口:类的实例是对象,无法满足“直接调用”的函数签名;而类的构造函数本身在严格模式下不允许直接调用,因此无法同时适配两种签名要求。
new.target是核心判断依据:这是ES6引入的特性,能精准区分函数是直接调用还是通过new调用,让我们在同一个函数体内处理两种逻辑。
内容的提问来源于stack exchange,提问作者Radu Szasz
相关产品推荐
相关产品推荐

