Дискриминационные союзы с логическими значениями в Typescript - PullRequest
2 голосов
/ 25 марта 2020

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

interface InitializingThing extends BaseThing {
    initialized: false;
    value: undefined;
}

interface InitializedThing extends BaseThing {
    initialized: true;
    value: number;
}

type Thing = InitializingThing | InitializedThing;

const thing: Thing = { initialized: false, value: undefined };
console.log(thing);

getThing().then((value: number) => {
    thing.value = value;
    thing.initialized = true;
}).then(() => {
    if (!thing.initialized) {
        return;
    }
    console.log(15 + thing.value);
});

(см. На Typescript площадка )

Однако это дает ошибки

Type 'number' is not assignable to type 'undefined'.(2322)
Type 'true' is not assignable to type 'false'.(2322)

По наведенному на console.log(thing) я вижу, что типом является InitializingThing вместо Thing! Кажется, это root проблемы, но я не уверен, почему компилятор TS сделает это.

Ответы [ 2 ]

3 голосов
/ 25 марта 2020

Ваш код в принципе работает нормально. Однако в вышеприведенном примере TS на самом деле немного «слишком умен» с его анализом потока управления . В следующем присвоении переменной

const thing: Thing = { initialized: false, value: undefined };

компилятор сужает тип thing до InitializingThing, интерпретируя его инициализатор. Также предполагается, что thing сохраняет этот тип, поскольку переменная доступна только для чтения / const. Вот почему возникает ошибка для переназначений в предложении then.

Если вы заставите thing действительно иметь тип Thing, данный пример будет скомпилирован снова:

const thing: Thing = { initialized: false, value: undefined } as Thing; // note the cast here
// or 
let thing: Thing = { initialized: false, value: undefined }; // switch to mutable `let`

Детская площадка

2 голосов
/ 25 марта 2020

В этой строке кода объект недопустим:

thing.value = value;

Теперь он имеет тип {initialized: false, value: number}, что неверно.

Вместо этого вам нужно изменить значения вместе:

thing = { value: value, initialized, true }

Но для этого вы обнаружите, что thing не может быть константой (потому что вы присваиваете ему новое значение). Вам нужно будет сделать это let.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...