在 TypeScript 中,我想从这样的常量派生类型
const iso3ToCountry = {
DEU: {
name: "Germany",
continent: "Europe",
language: "de",
},
GBR: {
name: "United Kingdom of Great Britain and Northern Ireland",
continent: "Europe",
language: "en",
},
} as const;
type ISOCode = keyof typeof iso3ToCountry // same as "DEU" | "GBR";
Run Code Online (Sandbox Code Playgroud)
但是,我还想确保对象的值实现以下接口:
interface CountryDetails {
name: string;
continent: string;
language: string;
}
Run Code Online (Sandbox Code Playgroud)
我发现实现这两个目标的唯一方法是使用辅助函数
function ensureType<T extends Record<string, CountryDetails>>(obj: T): T {
return obj;
}
const iso3ToCountry = ensureType({
DEU: {
name: "Germany",
continent: "Europe",
language: "de",
},
GBR: {
name: "United Kingdom",
continent: "Europe",
language: "en",
},
} as const);
type ISOCode = keyof typeof iso3ToCountry;
Run Code Online (Sandbox Code Playgroud)
现在ISOCode相当于"DEU" | "GBR"iso3ToCountry 中的每个值都必须有一个name,continent和一个language。
缺点是该ensureType函数将位于编译后的 JavaScript 中。我们向应用程序添加代码,只是为了解决一些编译时问题。
我可以在“iso3ToCountry”对象中实现类型检查以及派生键类型的能力,而无需添加保留在编译后的 JavaScript 中的代码吗?
您确实需要所谓的satisfies运算符,如microsoft/TypeScript#7481中所要求的那样,但这目前在 TypeScript 中不存在(截至 4.5)。您使用的通用辅助函数方法是一种非常常见的解决方法,特别是因为它几乎适用于任何表达式。发出的 JavaScript 中的额外函数调用通常不是什么大问题,但您正在寻找运行时影响为零的东西。
另一种解决方法是在与要检查的表达式类型相同的变量上使用typeof类型运算符来定义类型,编译器将成功或失败,具体取决于所需的约束。
您不能typeof在任意表达式上使用运算符;它必须是变量或变量的属性。因此,如果您需要声明新变量,此解决方法可能会对运行时产生一些影响。
由于您已经有一个名为iso3ToCountry正确类型的变量,因此不必定义新变量,因此不会对运行时产生影响。
这是一种方法:
type CheckIso3ToCountry<T extends Record<keyof T, CountryDetails> =
typeof iso3ToCountry> = void;
//^^^^^^^^^^^^^^^^^^^^ <-- you've got a problem with
// iso3ToCountry if and only if there's an error here
Run Code Online (Sandbox Code Playgroud)
这里的CheckIso3ToCountry<T>类型是一个虚拟类型,void无论如何都会计算结果。重要的部分是强制类型参数扩展的通用约束,以及 的通用参数默认值。只要后一种类型可以分配给前一种类型,一切都很好。TRecord<keyof T, CountryDetails>typeof iso3ToCountry
但如果你犯了一个错误iso3ToCountry:
const iso3ToCountry = {
DEU: {
name: "Germany",
continent: "Europe",
language: "de",
},
GBR: {
name: "United Kingdom of Great Britain and Northern Ireland",
continant: "Europe",
language: "en",
},
} as const;
Run Code Online (Sandbox Code Playgroud)
然后你会得到一个错误:
type CheckIso3ToCountry<T extends Record<keyof T, CountryDetails> =
typeof iso3ToCountry> = void; // error!
//~~~~~~~~~~~~~~~~~~~~ <--
// Property 'continent' is missing in type
// '{ readonly name: "United Kingdom of Great Britain and Northern Ireland";
// readonly continant: "Europe"; readonly language: "en"; }'
// but required in type 'CountryDetails'.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3548 次 |
| 最近记录: |