无限嵌套类型在 TypeScript 中

huangapple go评论64阅读模式
英文:

Infinit nested types in typescript

问题

我正在尝试定义一个匹配这个数据结构的接口/类型。

  1. 叶子属性的类型是 { dataType: string },例如 "tags"、"isRestricted"、"city"、"postalCode" 等。

  2. 非叶子属性具有其他非叶子属性的叶子属性。例如 "organism"、"collection" 和 "collectionAddress"。

能帮忙定义这个数据结构的接口或类型吗?非常感谢任何帮助!

英文:

I am trying to define a interface/type to match this data structure.

  1. The leaf properties are type of { dataType: string }, for example "tags", "isRestricted", "city", "postalCode" etc.

  2. The non-leaf properties have other non-leaf properties of leaf properties. For example, "organism", "collection", and "collectionAddress".

Can anyone help define an interface or type for this data structure? Much appreciated for any help!

{
  "sample": {
    "tags": { "dataType": "string[]" },
    "isRestricted": { "dataType": "boolean" },
    "organism": {
      "sex": { "dataType": "string" },
      "collection": {
        "collectionDate": {"dateType": "date"},
        "collectionAddress": {
          "addressLine": { "dataType": "string" },
          "city": { "dataType": "string" },
          "postalCode": { "dataType": "string" }
        }
      }
    }
  }
}

答案1

得分: 1

以下是您要的翻译部分:

听起来你想要一个字符串的递归记录到 `{ dataType: string }` 或其他记录。在这里使用如下方式很有诱惑力:

```ts
type Leaves<T> = Record<string, T | Leaves<T>>;

但你会得到一个错误,"Type circularly references itself"(查看此问题),因此我们需要将其扩展为一个映射类型:

type Leaves<T> = { [K in string]: T | Leaves<T> };

然后可以像这样使用它:

const data: Leaves<{ dataType: string }> = {
    sample: {
        tags: { dataType: "string[]" },
        isRestricted: { dataType: "boolean" },
        organism: {
            sex: { dataType: "string" },
            collection: {
                collectionDate: { dataType: "date" },
                collectionAddress: {
                    addressLine: { dataType: "string" },
                    city: { dataType: "string" },
                    postalCode: { dataType: "string" },
                },
            },
        },
    },
};

Playground


---

需要注意的是,此解决方案允许类似以下的内容:

```ts
{ dataType: { dataType: { dataType: "string" } } }

如果不希望出现这种行为,可以添加另一个映射类型来将 T 的所有键映射到 never

type Leaves<T> = { [K in string]: T | Leaves<T> } & { [K in keyof T]?: never };

然后在前面的代码段中,第一个 dataType 将报错,提示 { ... } 不能分配给类型 string

Playground

英文:

Sounds like you want a recursive record of strings to { dataType: string } or other records. It's tempting to use exactly that here:

type Leaves&lt;T&gt; = Record&lt;string, T | Leaves&lt;T&gt;&gt;;

but you'll get an error, "Type circularly references itself" (see this question), so we'll have to expand it into a mapped type:

type Leaves&lt;T&gt; = { [K in string]: T | Leaves&lt;T&gt; };

You could then use it like this:

const data: Leaves&lt;{ dataType: string }&gt; = {
    sample: {
        tags: { dataType: &quot;string[]&quot; },
        isRestricted: { dataType: &quot;boolean&quot; },
        organism: {
            sex: { dataType: &quot;string&quot; },
            collection: {
                collectionDate: { dataType: &quot;date&quot; },
                collectionAddress: {
                    addressLine: { dataType: &quot;string&quot; },
                    city: { dataType: &quot;string&quot; },
                    postalCode: { dataType: &quot;string&quot; },
                },
            },
        },
    },
};

Playground


It is important to note that this solution allows for things such as

{ dataType: { dataType: { dataType: &quot;string&quot; } } }

If you do not want this behavior, you may add another mapped type to map all the keys of T to never:

type Leaves&lt;T&gt; = { [K in string]: T | Leaves&lt;T&gt; } &amp; { [K in keyof T]?: never };

Then in the previous snippet, you will get an error on the first dataType saying that { ... } is not assignable to type string.

Playground

huangapple
  • 本文由 发表于 2023年3月9日 21:49:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/75685509.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定