区分元组未按预期工作

Discriminating tuple not working as expected

我刚刚从的回答中学到了使用鉴别元组作为参数的方法,但是当我在我的一些旧代码上尝试这个概念时,我发现我无法让它工作如我所料。考虑以下示例:

class Fraction {
    constructor(r: Rational) {
        /* Not important */
    }
}
type Rational = number | Fraction;

class Couple {
    private _x: Fraction;
    private _y: Fraction;

    constructor(c: Couple);
    constructor(x: Rational, y: Rational);
    constructor(...r: [Couple] | [Rational, Rational]) {
        if(r[0] instanceof Couple) r = [r[0]._x, r[0]._y]; // pay attention here
        this._x = new Fraction(r[0]);
        this._y = new Fraction(r[1]);
    }
}

我预计,在上面指示的行之后,TypeScript 应该得出结论 r 只能是 [Rational, Rational] 类型并且接下来的两行应该没有问题,但那是不是这样的。为什么会这样,如何在仍然使用元组想法的同时解决这个问题?

问题在于这个元组并不是真正的可区分联合。一个判别联合必须有一个判别式 属性,一个 属性 是一个判别式 属性 如果:

  1. 属性 是此处概述的文字类型 9163
  2. 联合类型的 属性 是判别式 属性 如果它的联合类型包含至少一个单元类型并且没有此处概述的可实例化类型 27695

查看this评论

如果我们向第一个元组添加一个额外的元素,我们可以将其转换为可区分的联合,从而满足上面概述的第二种情况:

class Fraction {
    constructor(r: Rational) {
        /* Not important */
    }
}
type Rational = number | Fraction;

class Couple {
    private _x: Fraction;
    private _y: Fraction;

    constructor(c: Couple);
    constructor(x: Rational, y: Rational);
    constructor(...r: [Couple, undefined?] | [Rational, Rational]) {
        if(r[1] === undefined) r = [r[0]._x, r[0]._y]; 
        this._x = new Fraction(r[0]); // ok
        this._y = new Fraction(r[1]); // ok
    }
}