英文:
Infinit nested types in typescript
问题
我正在尝试定义一个匹配这个数据结构的接口/类型。
-
叶子属性的类型是 { dataType: string },例如 "tags"、"isRestricted"、"city"、"postalCode" 等。
-
非叶子属性具有其他非叶子属性的叶子属性。例如 "organism"、"collection" 和 "collectionAddress"。
能帮忙定义这个数据结构的接口或类型吗?非常感谢任何帮助!
英文:
I am trying to define a interface/type to match this data structure.
-
The leaf properties are type of { dataType: string }, for example "tags", "isRestricted", "city", "postalCode" etc.
-
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" },
},
},
},
},
};
---
需要注意的是,此解决方案允许类似以下的内容:
```ts
{ dataType: { dataType: { dataType: "string" } } }
如果不希望出现这种行为,可以添加另一个映射类型来将 T
的所有键映射到 never
:
type Leaves<T> = { [K in string]: T | Leaves<T> } & { [K in keyof T]?: never };
然后在前面的代码段中,第一个 dataType
将报错,提示 { ... }
不能分配给类型 string
。
英文:
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<T> = Record<string, T | Leaves<T>>;
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<T> = { [K in string]: T | Leaves<T> };
You could then use it like this:
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" },
},
},
},
},
};
It is important to note that this solution allows for things such as
{ dataType: { dataType: { dataType: "string" } } }
If you do not want this behavior, you may add another mapped type to map all the keys of T
to never
:
type Leaves<T> = { [K in string]: T | Leaves<T> } & { [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
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论