Тип сужения потерян в последующем Array.prototype.map - PullRequest
3 голосов
/ 22 апреля 2020

Может кто-нибудь помочь объяснить следующие ошибки проверки типов:

interface Foo {
    kind: 'foo';
    a: string;
}

interface Bar {
    kind: 'bar';
    b: number;
}

type FooBar = Foo | Bar;

interface Container {
    ids: number[];
    fooBar: FooBar;
}

const cont: Container = {
    ids: [1, 2],
    fooBar: { kind: 'foo', a: 'a' },
};

switch (cont.fooBar.kind) {
    case 'foo':
        console.log(cont.fooBar.a); // OK

        cont.ids.map((id) => {
            console.log(`${id} - ${cont.fooBar.a}`);
            // Property 'a' does not exist on type FooBar
            //   Property 'a' does not exist on type Bar
        })
        break;
    case 'bar':
        console.log(cont.fooBar.b); // OK

        cont.ids.map((id) => {
            console.log(`${id} - ${cont.fooBar.b}`);
            // Property 'b' does not exist on type FooBar
            //   Property 'b' does not exist on type Foo
        })
        break;
}

Живой пример на детской площадке .

1 Ответ

2 голосов
/ 22 апреля 2020

Вы можете исправить это, набрав fooBar на локальный const и используя fooBar вместо cont.fooBar в switch:

const { fooBar } = cont; // <====
switch (fooBar.kind) {
    case 'foo':
        console.log(fooBar.a); // OK

        cont.ids.map((id) => {
            console.log(`${id} - ${fooBar.a}`); // OK now
        })
        break;
    case 'bar':
        console.log(fooBar.b); // OK

        cont.ids.map((id) => {
            console.log(`${id} - ${fooBar.b}`); // OK now
        })
        break;
}

Live copy

Первоначально я делал это в каждом case, но TypeScript доволен этим, как и выше.

Я думаю, это потому, что TypeScript не может знать наверняка, что обратный вызов является синхронным, и поскольку cont.fooBar может быть изменен другим кодом позже, если обратный вызов является асинхронным, нельзя быть уверенным, что суженный тип по-прежнему корректен. Захватить это местное удаляет это сомнение. Эта теория подтверждается тем фактом, что если вы сделаете его let { fooBar } = cont; вместо const { fooBar } = cont;, он не сможет снова сузить тип.

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