Различающий кортеж не работает должным образом - PullRequest
1 голос
/ 02 июля 2019

Я только что узнал метод использования различающего кортежа в качестве параметра из ответа на этот вопрос , но, когда я попробовал концепцию на некоторых из моих старых кодов, я обнаружил, что не могу его получить работать как я ожидал. Рассмотрим следующий пример:

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 Ответ

1 голос
/ 02 июля 2019

Проблема в том, что этот кортеж на самом деле не является дискриминационным объединением.Дискриминированный союз должен иметь свойство дискриминанта, свойство является свойством дискриминанта, если:

  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
    }
}
...