具有多个调用签名的overloaded function的实现是在打字脚本中正确地键入never.编写重载的标准方法是使用类似于function
statement的
function hash(data: string | Buffer): Buffer;
function hash(data: string | Buffer, encoding: BinaryToTextEncoding): string;
function hash(data: string | Buffer, encoding?: BinaryToTextEncoding) {
const hash = createHash("sha256");
hash.update(data);
if (encoding) {
return hash.digest(encoding); // okay
}
return hash.digest(); // okay
};
你不需要写type assertion,就像as any
一样.这在编译时没有错误,但这只是因为编译器只有loosely次根据调用签名判断实现.只要您返回类似于"a string
or a Buffer
"的内容,编译器就会接受它,即使它与encoding
参数无关:
function badHash(data: string | Buffer): Buffer;
function badHash(data: string | Buffer, encoding: BinaryToTextEncoding): string;
function badHash(data: string | Buffer, encoding?: BinaryToTextEncoding) {
return data; // also okay, even though this is not safe
};
你可以在microsoft/TypeScript#13235上读到这篇文章.对于编译器来说,要多次分析函数实现以确保分别满足每个调用签名,将会太复杂.因此,对于函数语句,它的错误是允许的,导致unsoundness.
另一方面,当你有一个像an arrow function这样的expression函数时,你会遇到相反的问题.编译器仍然不会 for each 调用签名分析一次实现;相反,它也会判断实现strictly,只有在返回类型适用于all调用签名时才接受它.对于函数表达式,它有限制方面的错误,导致了incompleteness.
因此,除非您的函数以某种方式返回string
and a Buffer
(例如,intersection type string & Buffer
),否则它会报告:
const hash: { // error! string | Buffer not assignable to Buffer
(data: string | Buffer): Buffer;
(data: string | Buffer, encoding: BinaryToTextEncoding): string;
} = (data: string | Buffer, encoding?: BinaryToTextEncoding) => {
const hash = createHash("sha256");
hash.update(data);
if (encoding) {
return hash.digest(encoding);
}
return hash.digest();
};
你可以在microsoft/TypeScript#47669岁时读到大约this期.建议以与重载函数语句相同的宽松方式判断重载函数表达式.但就目前而言,它不是语言的一部分,您需要一些类似类型断言或其他类型安全松动的东西.
如果您断言返回的每个值都是交集string & Buffer
,那么它将不会出错地进行编译(即使基本上不可能同时是string
和Buffer
):
const hash: {
(data: string | Buffer): Buffer;
(data: string | Buffer, encoding: BinaryToTextEncoding): string;
} = (data: string | Buffer, encoding?: BinaryToTextEncoding) => {
const hash = createHash("sha256");
hash.update(data);
if (encoding) {
return hash.digest(encoding) as (string & Buffer); // okay
}
return hash.digest() as (string & Buffer); // okay
};
或者,您可以使用单个as any
断言,由于the intentionally unsafe any
type的"传染性"性质,它会导致整个返回类型为any
,这与所有内容都兼容,包括string
和Buffer
:
const hash: {
(data: string | Buffer): Buffer;
(data: string | Buffer, encoding: BinaryToTextEncoding): string;
} = (data: string | Buffer, encoding?: BinaryToTextEncoding) => {
const hash = createHash("sha256");
hash.update(data);
if (encoding) {
return hash.digest(encoding);
}
return hash.digest() as any; // either return statement will do
};
或者,您可以在不使用断言的情况下仅将annotate the return value视为any
(这只是因为any
是不安全的,并且允许从几乎任何其他类型都可以赋值给and):
const hash: {
(data: string | Buffer): Buffer;
(data: string | Buffer, encoding: BinaryToTextEncoding): string;
} = (data: string | Buffer, encoding?: BinaryToTextEncoding): any => { // here
const hash = createHash("sha256");
hash.update(data);
if (encoding) {
return hash.digest(encoding);
}
return hash.digest()
};
这些方法中的任何一种都将在编译器停止抱怨的意义上"起作用".但没有一个是安全的.事实上,使用any
会使您更容易搞砸实现,而不会希望它被捕获:
const hash: {
(data: string | Buffer): Buffer;
(data: string | Buffer, encoding: BinaryToTextEncoding): string;
} = (data: string | Buffer, encoding?: BinaryToTextEncoding): any => {
return 123; // also acceptable because of any
};
同样,重载的函数实现从未真正得到正确判断.您可以在漏报和误报之间进行 Select ,前者是编译器无法捕获真正的错误,后者则是编译器抱怨并不真正存在的错误...修复这些假阳性只意味着你再次打开了假阴性的可能性.因此,采取哪种方法取决于你.
Playground link to code个