TypeScript 的 core.ts 如何在没有过载错误的情况下构建?
How does TypeScript's core.ts build without a overload error?
这几行代码...
export function sameFlatMap<T>(array: T[], mapfn: (x: T, i: number) => T | ReadonlyArray<T>): T[];
export function sameFlatMap<T>(array: ReadonlyArray<T>, mapfn: (x: T, i: number) => T | ReadonlyArray<T>): ReadonlyArray<T>;
export function sameFlatMap<T>(array: T[], mapfn: (x: T, i: number) => T | T[]): T[] {
let result: T[] | undefined;
if (array) {
for (let i = 0; i < array.length; i++) {
const item = array[i];
const mapped = mapfn(item, i);
if (result || item !== mapped || isArray(mapped)) {
if (!result) {
result = array.slice(0, i);
}
if (isArray(mapped)) {
addRange(result, mapped);
}
else {
result.push(mapped);
}
}
}
}
return result || array;
}
... 存在于 TypeScript 编译器实现源中的 line 702 of compiler/core.ts 上。
为什么编译时不会产生重载错误?
我问是因为我预计它会因下面第一个示例中显示的相同原因而出错——即尝试将 ReadonlyArray<T>
传递给期望 T[]
.
的参数
为什么不产生这个错误:
src/compiler/core.ts:702:21 - error TS2394: This overload signature is not compatible with its implementation signature.
702 export function sameFlatMap<T>(array: ReadonlyArray<T>, mapfn: (x: T, i: number) => T | ReadonlyArray<T>): ReadonlyArray<T>;
如果我在我的代码中尝试这样做,那么这是一个过载错误...
export function foo<T>(array: ReadonlyArray<T>): ReadonlyArray<T>;
export function foo<T>(array: T[]): T[] {
return array;
}
... 而这不是错误...
export function baz<T>(array: T[]): T[];
export function baz<T>(array: ReadonlyArray<T>): ReadonlyArray<T> {
return array;
}
...我想那是因为:
T[]
作为输入参数可以传递给期望 ReadonlyArray<T>
作为其输入参数的函数(反之亦然)
- 重载错误检查只检查输入参数的类型,不检查return类型
如果您检查 tsconfig-base.json,您会注意到并非所有严格选项都已启用。对于您的问题,最值得注意的是,strictFunctionTypes
未启用。
这意味着编译器将更加宽松地考虑函数兼容性,alowinf 函数参数与双变量相关(您可以阅读更多内容 here)。尽管 PR 没有明确提到重载,但它确实会影响函数签名的一般兼容性,因此它也会影响重载兼容性是有道理的。因此,例如,此分配在 strictNullChecks
下无效,但在没有它的情况下有效:
let fn : <T>(array: ReadonlyArray<T>) => ReadonlyArray<T> = function<T>(array: T[]): T[] {
return array;
}
这几行代码...
export function sameFlatMap<T>(array: T[], mapfn: (x: T, i: number) => T | ReadonlyArray<T>): T[];
export function sameFlatMap<T>(array: ReadonlyArray<T>, mapfn: (x: T, i: number) => T | ReadonlyArray<T>): ReadonlyArray<T>;
export function sameFlatMap<T>(array: T[], mapfn: (x: T, i: number) => T | T[]): T[] {
let result: T[] | undefined;
if (array) {
for (let i = 0; i < array.length; i++) {
const item = array[i];
const mapped = mapfn(item, i);
if (result || item !== mapped || isArray(mapped)) {
if (!result) {
result = array.slice(0, i);
}
if (isArray(mapped)) {
addRange(result, mapped);
}
else {
result.push(mapped);
}
}
}
}
return result || array;
}
... 存在于 TypeScript 编译器实现源中的 line 702 of compiler/core.ts 上。
为什么编译时不会产生重载错误?
我问是因为我预计它会因下面第一个示例中显示的相同原因而出错——即尝试将 ReadonlyArray<T>
传递给期望 T[]
.
为什么不产生这个错误:
src/compiler/core.ts:702:21 - error TS2394: This overload signature is not compatible with its implementation signature.
702 export function sameFlatMap<T>(array: ReadonlyArray<T>, mapfn: (x: T, i: number) => T | ReadonlyArray<T>): ReadonlyArray<T>;
如果我在我的代码中尝试这样做,那么这是一个过载错误...
export function foo<T>(array: ReadonlyArray<T>): ReadonlyArray<T>;
export function foo<T>(array: T[]): T[] {
return array;
}
... 而这不是错误...
export function baz<T>(array: T[]): T[];
export function baz<T>(array: ReadonlyArray<T>): ReadonlyArray<T> {
return array;
}
...我想那是因为:
T[]
作为输入参数可以传递给期望ReadonlyArray<T>
作为其输入参数的函数(反之亦然)- 重载错误检查只检查输入参数的类型,不检查return类型
如果您检查 tsconfig-base.json,您会注意到并非所有严格选项都已启用。对于您的问题,最值得注意的是,strictFunctionTypes
未启用。
这意味着编译器将更加宽松地考虑函数兼容性,alowinf 函数参数与双变量相关(您可以阅读更多内容 here)。尽管 PR 没有明确提到重载,但它确实会影响函数签名的一般兼容性,因此它也会影响重载兼容性是有道理的。因此,例如,此分配在 strictNullChecks
下无效,但在没有它的情况下有效:
let fn : <T>(array: ReadonlyArray<T>) => ReadonlyArray<T> = function<T>(array: T[]): T[] {
return array;
}