我有一个有趣的案例,从中央JSON数据存储动态定义类型将非常有用。让我解释一下。
我有一个包含品牌列表的json文件
// brands.json
{
"Airbus": {
"keywords": ["A320", "A380"],
"type": ["planes"]
},
"Jaguar": {
"keywords": ["fiesta"],
"origin": "UK",
"type": ["cars", "glasses"]
},
"Nissan": {
"keywords": ["qashqai"],
"type": ["cars"]
}
}
然后我有我的类型定义:
import brands from "./brands.json
type BrandNames= keyof typeof brands ;
type Brands = {
[P in BrandNames]: {
keywords: string[];
origin?: string;
type: string[];
}
};
我创建了一个CompanieNames类型,该类型会自动生成并等于"Airbus" | "Jaguar" | "Nissan"
。
到目前为止一切都很好...
现在,我想创建一个CarBrands类型,该类型将等于"Jaguar" | "Nissan"
。
可以进行type CarBrands = Exclude<CompanieNames, "Airbus">;
,但这不是动态的。
因此,我需要从Brands
中过滤掉所有具有嵌套type
属性的键,这些属性不包含字符串"cars"
。 / p>
有可能这样做吗?
答案 0 :(得分:2)
如果保留字符串文字类型的类型,我们可以做您想要的事情(即,仅提取在car
字段中具有types
的品牌)。但是,Typescript会将types
数组中的值的类型扩展为string
,因此当我们实际查看json对象的类型时,此信息对我们丢失了。
很有趣,使用3.4中的as const
(尚未发布)保留所有字符串文字类型,这就是解决方案的样子:
let data = {
"Airbus": {
"keywords": ["A320", "A380"],
"type": ["planes"]
},
"Jaguar": {
"keywords": ["fiesta"],
"origin": "UK",
"type": ["cars", "glasses"]
},
"Nissan": {
"keywords": ["qashqai"],
"type": ["cars"]
}
} as const;
type Data = typeof data;
type CarBrands = {
[P in keyof Data]: 'cars' extends Data[P]['type'][number] ? P : never
}[keyof Data]
同样,以上内容不适用于导入的json模块,因为typescript不会在字符串数组中保留文字类型,并且在编写本文时也没有办法告诉它这样做。