生成 Typescript 代码,可以访问 TypeScript 对象的未定义属性

问题描述 投票:0回答:1

我想创建一个类型,它允许访问对象的未定义属性,并为它们假设

any
的类型,并递归地执行此操作。让我用一个例子来说明这个问题。 (根据Darryl Noakes 的评论简化并更正了示例。)

const data = {a: "a", b: {c: 'hey'}}

type Data = typeof data & { [key: string]: any }

const dataOptional: Data = data

// This errors:) as expected, because the property "a" does not have such method
dataOptional.a.nonExistentStringMethod
// This two do not error:) as expected, because d has the correct type of "any"
dataOptional.d
dataOptional.d.nonExistentStringMethod
// This does error:( and that's the problem with this type
dataOptional.b.d

所以上述实现的问题是该语句不递归应用。重要的一点是,我事先有

data
的 JSON 值,然后我必须生成一些代码,最后,我可以导出原始
data
值,从而能够访问未定义的属性,如所述上面。

所以问题是,如何从 JSON 值获取到某些 TypeScript 代码,该代码以一种可以递归访问任何未定义属性的方式导出 JSON 值,并且访问的值将具有 any 的值,同时保持键入原始对象中定义的(嵌套或非嵌套)属性的数据。

typescript
1个回答
0
投票

您可以使用此实用程序类型:

type WithAny<T> = {
  [key: string]: any;
} & {
  [key in keyof T]: T[key] extends object ? WithAny<T[key]> : T[key]
}

它将以递归方式将给定类型中的任何对象类型与索引类型相交,以添加任何字符串键作为

any
。由于原始类型更具体(即更窄),因此这不会删除已知键的键入。

示例:

const data = {
  a: "a",
  b: {
    c: "hey",
  },
}

type AnyData = WithAny<typeof data>

const anyData: AnyData = data

anyData.a.foo // Error, expected
anyData.b.foo // No error, expected

/*
Pseudo-type of AnyData:
{
  a: string
  b: {
    c: string
    [key: string]: any
  }
  [key: string]: any
}
*/

TypeScript 游乐场


警告

这会将交集应用于任何对象类型,其中包括

Date
Map
等对象。如果您的数据包含这些对象,交集也会添加到它们中。
如果您的数据中有已知的对象类型,请务必更新
extends
检查以排除它们。如果您不知道可能存在什么,请在使用此答案中给出的代码之前了解您在做什么。

处理示例

Date

type WithAny<T> = {
  [key: string]: any
} & {
  [key in keyof T]: T[key] extends object
    ? T[key] extends Date
      ? T[key]
      : WithAny<T[key]>
    : T[key]
}

您可以继续嵌套这些检查,将它们放置在嵌套

WithAny
所在的位置。

© www.soinside.com 2019 - 2024. All rights reserved.