打字稿重载箭头功能不起作用
Typescript overload arrow function is not working
(我正在使用严格的空值检查)
我有以下带有重载类型的箭头函数:
type INumberConverter = {
(value: number): number;
(value: null): null;
};
const decimalToPercent: INumberConverter = (value: number | null): number | null => {
if (!value) {
return null;
}
return value * 100;
};
根据我从其他问题 (Can I use TypeScript overloads when using fat arrow syntax for class methods?) 的理解,这应该是有效的。尽管如此,我还是收到以下错误:
TS2322: Type '(value: number | null) => number | null' is not assignable to type 'INumberConverter'. Type 'number | null' is not assignable to type 'number'. Type 'null' is not assignable to type 'number'
如果我定期编写此函数(使用 function
关键字):
function decimalToPercent(value: null): null;
function decimalToPercent(value: number): number;
function decimalToPercent(value: number | null): number | null {
if (!value) {
return null;
}
return value * 100;
}
它没有错误。
我需要使用箭头函数所以 this
不会改变,我需要这个重载所以打字稿知道 decimalToPercent(1)
不能为空。
为什么它不像我那样工作,我该如何解决?
重载签名和实现签名之间的兼容性规则比赋值要宽松得多。
在这种情况下,您试图将可能 return null
的函数分配给具有禁止 return 空值的重载的函数((value: number): number;
).编译器会正确地发现这令人不安。对于重载,由于签名和实现都是作为一个单元编写的,因此编译器假定 'You know what you are doing'(正确与否)。
您可以通过多种方式解决它:
您可以使用类型断言,尽管您将放弃大多数类型检查以实现实现、签名兼容性:
type INumberConverter = {
(value: number): number;
(value: null): null;
};
const decimalToPercent = ((value: number | null): number | null => {
if (!value) {
return null;
}
return value * 100;
}) as INumberConverter;
您也可以像以前的 ES5
那样使用常规 function
并捕获 this
,尽管此解决方案意味着复制大量函数签名:
type INumberConverter = {
(value: number): number;
(value: null): null;
};
class X {
decimalToPercent: INumberConverter;
multiper = 100;
constructor() {
let self = this;
function decimalToPercent(value: number): number;
function decimalToPercent(value: null): null;
function decimalToPercent(value: number | null): number | null {
if (!value) {
return null;
}
// use self
return value * self.multiper;
};
this.decimalToPercent = decimalToPercent;
}
}
或者可能最简单的解决方案是在构造函数中使用 bind
并将函数编写为常规方法:
class X {
decimalToPercent(value: number): number;
decimalToPercent(value: null): null;
decimalToPercent(value: number | null): number | null {
if (!value) {
return null;
}
return value * this.multiper;
};
multiper = 100;
constructor() {
this.decimalToPercent = this.decimalToPercent.bind(this);
}
}
(我正在使用严格的空值检查)
我有以下带有重载类型的箭头函数:
type INumberConverter = {
(value: number): number;
(value: null): null;
};
const decimalToPercent: INumberConverter = (value: number | null): number | null => {
if (!value) {
return null;
}
return value * 100;
};
根据我从其他问题 (Can I use TypeScript overloads when using fat arrow syntax for class methods?) 的理解,这应该是有效的。尽管如此,我还是收到以下错误:
TS2322: Type '(value: number | null) => number | null' is not assignable to type 'INumberConverter'. Type 'number | null' is not assignable to type 'number'. Type 'null' is not assignable to type 'number'
如果我定期编写此函数(使用 function
关键字):
function decimalToPercent(value: null): null;
function decimalToPercent(value: number): number;
function decimalToPercent(value: number | null): number | null {
if (!value) {
return null;
}
return value * 100;
}
它没有错误。
我需要使用箭头函数所以 this
不会改变,我需要这个重载所以打字稿知道 decimalToPercent(1)
不能为空。
为什么它不像我那样工作,我该如何解决?
重载签名和实现签名之间的兼容性规则比赋值要宽松得多。
在这种情况下,您试图将可能 return null
的函数分配给具有禁止 return 空值的重载的函数((value: number): number;
).编译器会正确地发现这令人不安。对于重载,由于签名和实现都是作为一个单元编写的,因此编译器假定 'You know what you are doing'(正确与否)。
您可以通过多种方式解决它:
您可以使用类型断言,尽管您将放弃大多数类型检查以实现实现、签名兼容性:
type INumberConverter = {
(value: number): number;
(value: null): null;
};
const decimalToPercent = ((value: number | null): number | null => {
if (!value) {
return null;
}
return value * 100;
}) as INumberConverter;
您也可以像以前的 ES5
那样使用常规 function
并捕获 this
,尽管此解决方案意味着复制大量函数签名:
type INumberConverter = {
(value: number): number;
(value: null): null;
};
class X {
decimalToPercent: INumberConverter;
multiper = 100;
constructor() {
let self = this;
function decimalToPercent(value: number): number;
function decimalToPercent(value: null): null;
function decimalToPercent(value: number | null): number | null {
if (!value) {
return null;
}
// use self
return value * self.multiper;
};
this.decimalToPercent = decimalToPercent;
}
}
或者可能最简单的解决方案是在构造函数中使用 bind
并将函数编写为常规方法:
class X {
decimalToPercent(value: number): number;
decimalToPercent(value: null): null;
decimalToPercent(value: number | null): number | null {
if (!value) {
return null;
}
return value * this.multiper;
};
multiper = 100;
constructor() {
this.decimalToPercent = this.decimalToPercent.bind(this);
}
}