【问题标题】:How to make a TypeScript type guard without any or object?如何制作没有任何或对象的 TypeScript 类型保护?
【发布时间】:2020-06-05 04:39:00
【问题描述】:

我正在使用 typescript-eslint v3.1.0 并且在 TypeScript 中具有以下类型保护功能:

interface JWTPayload {
    sub: number;
}

function isJWTPayload(obj: unknown): obj is JWTPayload {
    if (typeof obj !== 'object') {
        return false;
    }

    // eslint-disable-next-line @typescript-eslint/ban-types
    const obj2 = obj as object;

    if (!('sub' in obj2)) {
        return false;
    }

    const obj3 = obj2 as JWTPayload;

    if (!Number.isInteger(obj3.sub)) {
        return false;
    }

    return true;
}

我的问题是:在我想象的常见情况下禁用 lint 规则感觉不好。有没有可以避免这种情况的 TypeScript 模式?

一些背景:

正在被禁用的 typescript-eslint 规则是在 https://github.com/typescript-eslint/typescript-eslint/pull/848 中引入的,其中认为“99.9% 的情况下,您不想使用 [“object” 类型],而广大大多数代码库都不想使用它”。他们为什么会这样说?似乎每当您验证用户输入时都会使用它。有没有其他方法可以在不强制转换为“任何”的情况下做到这一点?

【问题讨论】:

    标签: typescript eslint


    【解决方案1】:

    我找到了一个没有any 也没有断言的解决方案:

    type Message = {
      text: string;
    }
    
    function isObject(value: unknown): value is Record<string, unknown> {
      return typeof value === 'object' && value !== null;
    }
    
    function isMessage(value: unknown): value is Message {
      return isObject(value) && typeof value["text"] === 'string';
    }
    

    这是有效的,因为第一个类型保护正确地检测到了预期的对象。好的部分是isObject 可以在任何其他类型保护中重用。

    【讨论】:

    • 这也是我在继续解决这个问题几个月后决定使用的。我所有的复杂类型守卫现在都是由A &amp;&amp; B &amp;&amp; C &amp;&amp; D 组成的单行表达式,其中 A/B/C/D 是守卫(也就是您描述的形式)。 TypeScript 编译器从左到右考虑每个守卫,因此它们可以相互构建。它仍然感觉不是最佳的,但它避免了对强制类型转换/类型断言的所有需要​​,并且 linter 对此很满意。
    【解决方案2】:

    typeof is a type-guard 本身。所以你可以移动if块内的逻辑:

    function isJWTPayload(obj: unknown): obj is JWTPayload {
        if (typeof obj === 'object' && obj) {
            if (!('sub' in obj)) {
                return false;
            }
    
            const payload = obj as JWTPayload;
            if (Number.isInteger(payload.sub)) {
                return true;
            }
        }
    
        return false;
    }
    

    Playground

    我也会删除!('sub' in obj) 检查,因为它没有意义。如果subundefinedNumber.isInteger(undefined) 也会返回false

    【讨论】:

    • 这仍在使用断言,这意味着它也不是完全“安全”的。我不确定没有它们是否可行,但这个例子仍然与使用 any 的类型保护没有区别
    猜你喜欢
    • 2016-01-18
    • 1970-01-01
    • 2023-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多