TypeScript构造函数签名不兼容错误原因咨询
Hey Andrew,我来帮你把这个错误的来龙去脉理清楚!
首先,咱们先拆解一下你看到的错误信息:
Argument of type 'typeof AuthLoaderService' is not assignable to parameter of type 'new () => AuthLoaderService'.
Types of construct signatures are incompatible.
Type 'new ({ withoutAuth, scripts, setProxy }: initParams) => AuthLoaderService' is not assignable to type 'new () => AuthLoaderService'
这个报错的核心原因,是你传给super()的AuthLoaderService构造函数,和ServerHTTPService要求的构造函数类型不匹配,具体来说:
- 你定义的
ServerHTTPService构造函数第一个参数,要求的是new () => T——这是一个「不需要任何参数就能实例化的构造函数类型」。 - 但
AuthLoaderService的构造函数签名其实是带参数的:因为它继承了HttpLoaderService,而HttpLoaderService的构造函数必须接收一个initParams类型的参数。哪怕AuthLoaderService自己没写构造函数,TypeScript也会自动继承父类的构造函数逻辑,所以它的构造函数完整签名是new ({ withoutAuth, scripts, setProxy }: initParams) => AuthLoaderService。
当你在AuthenticationServerService里把AuthLoaderService传给super()时,就相当于把一个「必须传参才能实例化的类」,塞给了一个要求「无参就能实例化的类」的参数位置,TypeScript自然会抛出类型不兼容的错误。
至于为什么错误信息会提到HttpLoaderService的构造函数?那是因为AuthLoaderService没有自定义构造函数,它的构造函数完全继承自HttpLoaderService,所以TypeScript会溯源到父类的构造函数签名,来明确告诉你不兼容的具体点。
解决思路参考
你可以从两个方向调整代码来修复这个错误:
方向一:修改
ServerHTTPService的参数类型,适配带参构造函数
把ServerHTTPService构造函数的第一个参数类型,从new () => T改成和HttpLoaderService匹配的带参构造函数类型:class ServerHTTPService<T extends HttpLoaderService> extends ServerBaseService<T> { constructor( private readonly _createClasss: new (params: initParams) => T, // 改为带参构造函数类型 private readonly withoutAuth: boolean, private readonly setProxy: boolean, private readonly isKubee: boolean ) { super(_createClasss, isKubee) } }方向二:让
AuthLoaderService支持无参实例化
给HttpLoaderService的构造函数添加参数默认值,或者把initParams的所有属性改成可选(包括原本必填的setProxy),这样它就能被无参实例化了:// 方案1:给构造函数参数加默认值 class HttpLoaderService extends LoaderService { constructor({ withoutAuth, scripts, setProxy }: initParams = {} as initParams) { super() } } // 方案2:修改initParams,让所有属性可选 interface initParams { withoutAuth?: any; scripts?: any; setProxy?: any; // 把setProxy也改成可选 }
备注:内容来源于stack exchange,提问作者Andrew M

