为什么重新排序类型时交集会发生变化?

Ber*_*rto 8 typescript

如果这是一个非常基本的问题,我很抱歉。我正在自学打字稿,根据我的教程,交叉点中类型的顺序应该无关紧要,例如A & B并且B & A应该是相同的类型。

但是我偶然发现了这种边缘情况,其中类型的顺序确实很重要,尽管我不明白为什么。

abstract class Test
{
    constructor(a: string, b: boolean)
    { }
}

type A = typeof Test;
type B = new (...args: unknown[]) => unknown;

type AB = ConstructorParameters<A & B>; // unknown[]
type BA = ConstructorParameters<B & A>; // [a: string, b: boolean]
Run Code Online (Sandbox Code Playgroud)

在这种特殊情况下,顺序如何影响结果类型?

还有什么我应该注意的边缘情况吗?

谢谢你。

cap*_*ian 0

摘自文档

当从具有多个调用签名的类型(例如重载函数的类型)进行推断时,将从最后一个签名进行推断(这可能是最允许的包罗万象的情况)。无法根据参数类型列表执行重载决策。

您可以在这里找到更多解释

当你对两个函数进行交集时 - 这意味着你进行了重载。

请参阅下一个示例:

type A = (a: number) => number
type B = (b: string) => string
type C = (c: any) => any
declare var foo: A & B & C

foo(2) // number
foo('2') // string
foo({}) // any 
Run Code Online (Sandbox Code Playgroud)

上面的代码等于:

    function bar(a: string): string;
    function bar(a: number): number;
    function bar(a: any): any;
    function bar(a: number | string | any) {
        return null as any

    }
    bar(2); // number
    bar('2') // string
    bar({}) // any
Run Code Online (Sandbox Code Playgroud)

请记住,我a:any在最后放的不太具体。它按预期工作。

但是,如果我把它放在开头呢:

    function bar(a: any): any;
    function bar(a: string): string;
    function bar(a: number): number;
    function bar(a: number | string | any) {
        return null as any

    }
    bar(2); // any
    bar('2') // any
    bar({}) // any
}
Run Code Online (Sandbox Code Playgroud)

所有返回类型都是any. 因为一开始就没有具体的重载。

同样在这里:


type A = (a: number) => number
type B = (b: string) => string
type C = (c: any) => any
declare var foo: C & B & A

foo(2) // any
foo('2') // any
foo({}) // any 
Run Code Online (Sandbox Code Playgroud)

更新

让我们深入探讨一下ConstructorParameters。这是什么意思?

// this is what ConstructorParameters doing under the hood
type Check = A extends (a: infer A) => any ? A : never // number
type Check2 = (A & B) extends (a: infer A) => any ? A : never // string
type Check3 = (A & B & C) extends (a: infer A) => any ? A : never // any
Run Code Online (Sandbox Code Playgroud)

它只需要最后一个相交的项目并推断它的参数。

因此,如果我将其A作为最后一项,它将仅推断A参数:

    type Check4 = (C & B & A) extends (a: infer A) => any ? A : never // number

Run Code Online (Sandbox Code Playgroud)

因此,如果您正在执行函数的交集 - 您应该将 is 视为重载。

边缘情况:如果您有带有泛型的函数类型 - 交集,它可能不起作用。我不知道/不明白为什么。