嵌套的switch语句可以在TypeScript中详尽无遗吗?

时间:2018-01-05 16:02:12

标签: typescript switch-statement control-flow union-types

看起来以下代码没有在TypeScript中键入检查。

interface A {
    type: 'a',
    number: Number
}

interface B {
    type: 'b',
    number: Number
}

type Letter = A | B

interface One {
    type: 'one'
}

interface Two {
    type: 'two'
}

type Number = One | Two;


function we(letter: Letter): boolean { // claims boolean isn't always returned
    switch (letter.type) {
        case 'a':
            return true;

        case 'b':
            const number = letter.number;
            switch (number.type) {
                case 'one':
                    return true;
                case 'two':
                    return true;
            }
    }
}

我可以在内部开关上添加默认设置以使其正常工作但我很惊讶我需要让平板开关正常工作。到底发生了什么?

1 个答案:

答案 0 :(得分:0)

这里的问题是,您还没有处理数据不是您声明的数据的情况。也许在任何地方都可以演员阵容然后分配letter.type='c'。或者就此而言,只需将其称为:

we({type: 'c'} as any as Letter);

双重演员确保您不会收到编译器警告,但这不是您在函数中允许的情况。

以下是对其进行排序的一种方法:

function exhaustiveCheck(value: never): never {
  throw(new Error('switch was not exhaustive'));
}

function we(letter: Letter): boolean {
    switch (letter.type) {
        case 'a':
            return true;

        case 'b':
            const number = letter.number;
            switch (number.type) {
                case 'one':
                    return true;
                // case 'two':
                //     return true;
                default:
                  return exhaustiveCheck(number);
            }
        default: {
          return exhaustiveCheck(letter);
        }
    }
}

这确保了在运行时,如果您获得的数据不是所描述的类型系统,则会检查并抛出错误,但在编译时它还可以确保您已经详尽地处理了所有情况。 / p>

当我编写上面的代码时,对exhaustiveCheck(number)的调用会出现编译时错误,取消注释它上面的两行,错误就会消失。接受对exhaustiveCheck(letter)的第二次调用是因为在默认情况下我们已经涵盖了AB这两种类型,因此剩下的唯一情况是letter具有类型never:这意味着就类型系统而言,它永远不会发生,即使在运行时也可能发生。