如何解决如何从 TypeScript 中的对象数组创建类型?
给定一个 countries
数组,如下所示:
const countries = [
{ name: "Australia",code: "AU" },{ name: "Japan",code: "JP" },{ name: "Norway",code: "NO" },{ name: "Russian Federation",code: "RU" }
];
生成以下类型的最简单方法是什么?
type CountryCodes = "" | "AU" | "JP" | "NO" | "RU";
注意:有一个额外的空字符串。
解决方法
虽然从 JS 的角度来看这个函数是没有用的。能够将代码统一为一种。
function createCountries<T extends string>(
contries: { name: string; code: T }[],): { name: string; code: T }[] {
return contries;
}
const countries = createCountries([
{ name: "Australia",code: "AU" },{ name: "Japan",code: "JP" },{ name: "Norway",code: "NO" },{ name: "Russian Federation",code: "RU" }
]);
type CountryCodes = "" | (typeof countries)[number]["code"]; // "" | "AU" | "JP" | "NO" | "RU";
// Example - How to use the type
function getCountryByCode(code: CountryCode): Country | undefined {
return countries.find(country => country.code == code);
}
countries
的类型:
{
name: string;
code: "AU" | "JP" | "NO" | "RU";
}[]
没有进一步的信息,这是你能做的最好的......
type Countries = { name: string; code: string }[];
const countriesAbc = [
{ name: "Australia",code: "RU" }
] as const;
const countries: Countries = [...countriesAbc];
type CountryCodes = "" | (typeof countriesAbc)[number]["code"]; // "" | "AU" | "JP" | "NO" | "RU";
,
首先,如果不对您的输入数据集类型稍加修改,则无法实现您想要的。正如 jonsharpe's comment 正确声明的那样,此处数组成员的类型扩展为 { name: string; code: string; }
。这可以通过 as const
断言轻松解决:
const countries = [
{ name: "Australia",code: "RU" }
] as const;
现在数组本身被认为是一个元组,每个成员的属性也被设置为 readonly
。之后,您只需要一个映射类型来提取元组的值(通常使用 T[number]
完成),获取 code
成员的类型并从中构建联合:
type CountryCodes<T> = {
[ P in keyof T ] : T[P] extends { code: string } ? T[P]["code"] : never
}[keyof T & number] | "";
其中 T[P] extends { code: string }
约束确保我们可以使用 T[P]
索引 "code"
。结果正是你想要的(请注意,一切都是纯粹在类型系统中完成的):
type cc = CountryCodes<typeof countries>; //type cc = "" | "AU" | "JP" | "NO" | "RU"
使用 4.1 的 key remapping 功能的更简洁版本:
type CountryCodes<T> = keyof {
[ P in keyof T as T[P] extends { code: string } ? T[P]["code"] : never ] : T[P]
} | "";
,
你可以用其他方式来做
type CountryCodes = "" | "AU" | "JP" | "NO" | "RU";
interface Country {name: string; code: CountryCodes}
// Alternatively
// type Country = {name: string; code: CountryCodes}
const countries: Array<Country> = [
{ name: "Australia",code: "DE" },// COMPILE ERROR
{ name: "Japan",code: "RU" }
];
甚至更好
type NotEmptyCountryCodes = "AU" | "JP" | "NO" | "RU";
type CountryCodes = "" | NotEmptyCountryCodes;
interface Country {name: string; code: NotEmptyCountryCodes}
// Alternatively
// type Country = {name: string; code: NotEmptyCountryCodes}
const countries: Array<Country> = [
{ name: "Australia",code: "" },// COMPILE ERROR
{ name: "Norway",code: "RU" }
];
,
我认为从域的角度来看,它可能希望国家代码的变化更少,国家名称更灵活。如果您的问题只是从地图列表中创建联合字符串类型,另一种方法会更好。
从 const 列表创建联合类型 CountryCode(这在之后很有用):
const countryCodeList = ["AU","JP","NO","RU"] as const;
type CountryCode = "" | (typeof countryCodeList)[number];
用国家代码定义国家:
type Country = { name: string; code: CountryCode};
与 in 一起使用时,既安全又灵活:
// mock of date access.
const fetchByCode = (code: CountryCode,lang: string) : string => {
return "name of " + code;
};
// create county data from code list.
const createCountries = () : Country[] => {
return countryCodeList.map((code) => {
const name = fetchByCode(code,'en');
return {name,code}
});
};
// use country data.
const countriesEn = createCountries()
console.log(countriesEn);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。