【问题标题】:Typescript check if property in object in typesafe way打字稿检查对象中的属性是否以类型安全的方式
【发布时间】:2018-09-17 08:09:36
【问题描述】:

代码

const obj = {};
if ('a' in obj) console.log(42);

不是打字稿(没有错误)。我明白为什么会这样。此外,在 TS 2.8.1 中,“in”用作类型保护。

但是,有没有办法检查属性是否存在,但如果属性没有在obj的接口中定义,则会出错?

interface Obj{
   a: any;
}

我不是在谈论检查未定义...

【问题讨论】:

标签: javascript typescript types undefined


【解决方案1】:

您可以围绕 hasOwnProperty 实现自己的包装函数,该函数确实会缩小类型。

function hasOwnProperty<T, K extends PropertyKey>(
    obj: T,
    prop: K
): obj is T & Record<K, unknown> {
    return Object.prototype.hasOwnProperty.call(obj, prop);
}

我在这里找到了这个解决方案: TypeScript type narrowing not working when looping

【讨论】:

    【解决方案2】:

    以下handle 函数检查假设的服务器响应类型安全方式:

    /**
     * A type guard. Checks if given object x has the key.
     */
    const has = <K extends string>(
      key: K,
      x: object,
    ): x is { [key in K]: unknown } => (
      key in x
    );
    
    function handle(response: unknown) {
      if (
        typeof response !== 'object'
        || response == null
        || !has('items', response)
        || !has('meta', response)
      ) {
        // TODO: Paste a proper error handling here.
        throw new Error('Invalid response!');
      }
    
      console.log(response.items);
      console.log(response.meta);
    }
    

    Playground Link。函数has 可能应该保存在单独的实用程序模块中。

    【讨论】:

    • 虽然这不是类型安全的。如果定义response: {'a': number}has('items', response) 不会产生预期的编译时错误。
    • Erm... 当您无法控制函数handle 的参数类型时,我已经发布了解决方案。例如,这可能是 API 端点处理程序——每个人都可能不小心在那里发送无效数据。这就是为什么handle 接受unknown 类型的参数(这意味着“一切,我不知道是什么”)。这里的类型安全意味着您无法(在编译时)在不检查其类型的情况下使用response。例如。第 24 行中的 here response.somethingElse 在没有类型检查的情况下被使用,TypeScript 对此抱怨。
    • 哦,所以你的意思是“类型安全”的方式与我想象的完全不同。很酷,感谢您的回复!
    【解决方案3】:

    您不会收到错误消息,因为您使用字符串来检查属性是否存在。

    你会这样得到错误:

    interface Obj{
       a: any;
    }
    
    const obj: Obj = { a: "test" };
    
    if (obj.b)          // this is not allowed
    if ("b" in obj)     // no error because you use string
    

    如果您希望类型检查适用于字符串属性,您可以添加 index signatures using this example

    【讨论】:

    • 但是“if (obj.b)”也不允许未定义。属性不存在和未定义之间存在差异。我只想检查该属性是否以类型安全的方式存在。
    • 类型系统已经定义了属性是否存在,不需要自己去检查。当对象可以是多种类型时使用类型保护,例如:const obj: Thing | OtherThing
    • 没有,如果我有一个接口 { a?: any; },我不知道该属性是否存在。如果我从我无法控制的服务器(例如)获得一个对象,我永远不知道存在什么属性。我只想以类型安全的方式区分实际未定义或根本不存在的属性!
    • 如果您不知道您的 JSON 数据是什么样的,您可以使用console.log(o.hasOwnProperty("a")) 来查看属性是否存在。如果它存在但未定义,那么它仍然会返回 true。
    • 仍然不是类型安全检查,但您的答案是最好的,因为只有一个。而且我总是可以编写一个函数来执行类型安全的“输入”检查(使用 typescript keyof 语法)
    猜你喜欢
    • 2019-06-15
    • 2020-04-28
    • 1970-01-01
    • 2020-10-14
    • 2021-12-06
    • 2015-12-13
    • 2022-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多