【问题标题】:Typescript type safety in conditional union type switch typing条件联合类型开关类型中的打字稿类型安全
【发布时间】:2023-03-28 16:05:02
【问题描述】:

我有一个简单的函数,将联合类型和 boolean 作为参数,但无法让它由 Typescript 键入。

我有这个代码 (playground here):

type A = 'a' | 'A';

function f(a: A, b: boolean): string {
    if (b) {
        switch (a) {
            case 'a': return '';
            case 'A': return '';
        }
    } else {
        switch (a) {
            case 'a': return '';
            case 'A': return '';
        }
    }
}

编译器(启用strictNullChecks 时)告诉我Function lacks ending return statement and return type does not include 'undefined'.

我真的不想添加default 案例,因为这里的目标是确保当我在A 中添加新类型时,我在f 中正确处理它们。而且我没有看到我缺少哪个分支。

我可以通过写作来解决它(请参阅链接的游乐场):

function g(a: A): string {
    switch (a) {
        case 'a': return '';
        case 'A': return '';
    }
}

function f2(a: A, b: boolean): string {
    if (b) {
        return g(a);
    } else {
        return g(a);
    }
}

(当然在现实生活中我需要两个不同的 g 函数,但对于打字问题这并不重要)。

如何让 typescript 编译 f 而不引入像 g 这样的中间函数?

【问题讨论】:

    标签: typescript switch-statement union-types


    【解决方案1】:

    您可以添加 default 案例来修复它,例如

    function f(a: A, b: boolean): string {
        if (b) {
            switch (a) {
                case 'a': return '';
                case 'A':
                default: return '';
            }
        } else {
            switch (a) {
                case 'a': return '';
                case 'A':
                default: return '';
            }
        }
    }
    

    您还可以使用 never 类型通过返回它来修复它,例如

    function f(a: A, b: boolean): string {
        if (b) {
            switch (a) {
                case 'a': return '';
                case 'A': return '';
                default:
                    const _exhaustiveCheck: never = a;
                    return _exhaustiveCheck;
            }
        } else {
            switch (a) {
                case 'a': return '';
                case 'A': return '';
                default:
                    const _exhaustiveCheck: never = a;
                    return _exhaustiveCheck;
            }
        }
    }
    

    【讨论】:

    • 您的“从不”解决方案确实是我想要的,因为它在这里编译并且如果我在 A 中添加一个新类型就会失败,这就是重点。您的第一个解决方案很危险,因为它并没有真正对 A 进行类型检查(当我在 A 中添加新类型的那一天,它将应用默认行为,尽管我肯定想在这里以不同的方式处理它)。
    • @jolivier 是,但never 在早期版本中不可用。
    猜你喜欢
    • 2017-05-18
    • 1970-01-01
    • 2018-12-06
    • 2022-01-22
    • 2020-06-25
    • 1970-01-01
    • 2019-05-03
    • 1970-01-01
    • 2019-08-27
    相关资源
    最近更新 更多