打字稿检查对象中的属性是不是以类型安全的方式

Posted

技术标签:

【中文标题】打字稿检查对象中的属性是不是以类型安全的方式【英文标题】: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;

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

【问题讨论】:

How to determine whether an object has a given property in javascript的可能重复 【参考方案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': numberhas('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 语法)

以上是关于打字稿检查对象中的属性是不是以类型安全的方式的主要内容,如果未能解决你的问题,请参考以下文章

打字稿为“对象”分配特定类型而不是“任何”

转换对象属性,以便在打字稿中保留隐式类型

打字稿,合并对象类型?

如何使用打字稿中的查找来推断类型化的 mapValues?

打字稿:检查类型是不是为联合

打字稿:如何根据对象键/值类型在 ES6 映射中创建条目