typescript - 如何在 TypeScript 中创建具有最少强制属性的接口/类型?
问题描述
链接到最小可重现示例:https ://tsplay.dev/mL90eW
我有这个数据形状,我想在 TypeScript 中强制执行以下要求
- 必须有第一个要调用的字段
valueLabel
(此处为 YearQtr) - 必须至少具有我要调用的其他三个字段之一
nameLabel
(房屋、单元、土地)
const data: [
{ YearQtr: '2000Q1', House: '100', Unit: '200', Land: '300' },
{ YearQtr: '2000Q2', Unit: '400' },
{ YearQtr: '2000Q4', House: '500', Land: '600' },
{ YearQtr: '2001Q2', Unit: '700', Land: '800' },
我在 TypeScript 中为它定义了一个类型,但这也允许输入错误(参见下面示例中的最后三行:
type StackbarDatum = {
[key: string]: string
}
const data: StackbarDatum[] = [
{ YearQtr: '2000Q1', House: '100', Unit: '200', Land: '300' },
{ YearQtr: '2000Q2', Unit: '400' },
{ YearQtr: '2000Q4', House: '500', Land: '600' },
{ YearQtr: '2001Q2', Unit: '700', Land: '800' },
{ YearQtr: '2002Q1', House: '900', Unit: '1000' },
{ }, // this should not be allowed
{ YearQtr: '2002Q1' }, // this should not be allowed
{ House: '900', Unit: '1000' }, // this should not be allowed
]
我想知道如何以类型安全的方式正确地做到这一点。
解决方案
听起来你想要这样的联合类型:
type StackbarDatum = {
YearQtr: string;
House: string;
Unit?: string;
Land?: string;
} | {
YearQtr: string;
House?: string;
Unit: string;
Land?: string;
} | {
YearQtr: string;
House?: string;
Unit?: string;
Land: string;
}
如果你有很多属性要强制它们选择 1 个或多个,那么这个联合可能会有点麻烦。在这种情况下,您可以使用映射类型来做类似的事情。例如(受这篇文章的启发):
type AtLeastOne<T> = { [K in keyof T]: Pick<T, K> }[keyof T]
type StackbarDatum = {
YearQtr: string
} & AtLeastOne<{
House: string;
Unit: string;
Land: string;
}>
你谈论使这个通用。如果你的意思是你想要一个辅助类型来吐出这种格式的其他类型,那么像下面这样的东西可以工作:
type Datum<ValueLabel extends string, NameLabel extends string> = {
[K in ValueLabel]: string
} & AtLeastOne<{
[K in NameLabel]: string
}>
type StackbarDatum = Datum<'YearQtr', 'House' | 'Unit' | 'Land'>;
type OtherDatum = Datum<'Foo', 'Money' | 'Time' | 'Mojo'>;
请注意,您仍然需要在编译时知道属性的名称,否则 typescript 无能为力。
推荐阅读
- java - 在 tomcat 服务器中运行 servlet XQuery 时出现空白页面
- java - 使用 Apache POI 设置 Excel 工作表散点图标记图标的颜色
- java - 是否可以在 Windows 10 中为 AWT 应用程序提供清晰的任务栏图标
- database - 智能家居中的区块链使用
- spring - 有没有人将 Spring Security 从 3.1.2 迁移到 5.1.4
- coq - 定理蕴涵的coq语法
- ruby - 基于 Chef 版本的 Cookbook 依赖项
- javascript - 是否可以检测网络应用程序上的 android 后退按钮?
- sql - 如何在不影响生产数据库的情况下生成1000万行表的CSV文件?
- php - 在 laravel 中为接收部分交付的产品创造条件