Typescript 基于另一个属性添加额外的类型属性
#1我有一个对象列的类型。列可以是可过滤的,也可以是不可过滤的,如果Typescript 基于另一个属性添加额外的类型属性,typescript,types,discriminated-union,Typescript,Types,Discriminated Union,#1我有一个对象列的类型。列可以是可过滤的,也可以是不可过滤的,如果isFilterable为true,则类型Column应要求:filterType、isTopBarFilter?和选项(但仅当filterType为'SELECT'--2) 我使用types-union来完成这样的类型,它几乎可以正常工作 type FilterableColumn = { isFilterable: true; filterType: 'SELECT' | 'TEXT' | 'DATE'; opt
isFilterable
为true
,则类型Column
应要求:filterType
、isTopBarFilter?
和选项
(但仅当filterType
为'SELECT'
--2)
我使用types-union来完成这样的类型,它几乎可以正常工作
type FilterableColumn = {
isFilterable: true;
filterType: 'SELECT' | 'TEXT' | 'DATE';
options: string[];
isTopBarFilter?: boolean;
};
type NonFilterableColumn = {
isFilterable: false;
};
type Column = (NonFilterableColumn | FilterableColumn) & {
name: string;
};
但是:
正如我前面提到的(#2)列
应该需要选项
,只有当过滤器类型
是选择的时候。我曾尝试使用类型联合来实现这一点,但它变得很奇怪:
如果我将isFilterable
设置为false,TS不会提示不需要的属性(这是好的),但如果我通过了这些不需要的道具(这是坏的),也不会显示错误
我的解决方案还强制通过isFilterable
,即使它是false
,正如我上面提到的,我只想在它是true
时通过它
有没有办法改进我的解决方案(或其他解决方案)以实现我在开始时所描述的目标(#1)?让我们看看分布规律如何影响您案例中的交点和并集的解算方式。第一,以下几点:
type OuterUnionMemberA=(UnionMemberA | UnionMemberB)&IntersectedA;
相当于:
键入OuterUnionMemberA=(UnionMemberA和IntersectedA)|(UnionMemberB和IntersectedA);
这反过来又使我们得出以下结论:
type ComplexType=(outerRunionMemberA | IntersectedB)&outerPrinterSected;
相当于这个复杂的联合体:
type ComplexType=(UnionMemberA和IntersectedA和OuterIntersected)|(UnionMemberB和IntersectedA和OuterIntersected)|(IntersectedB和OuterIntersected);
让我们手动解析别名,看看它给我们留下了什么:
type ComplexType={
filterType:'选择';
选项:字符串[];
isFilterable:true;
extrop?:布尔值;
名称:字符串;
} | {
过滤器类型:“文本”|“日期”|“编号”;
isFilterable:true;
extrop?:布尔值;
名称:字符串;
} | {
isFilterable:false;
名称:string
}
为了验证我们对这是相同类型的期望,让我们做一个等式测试:
type isSupertype=ComplexType扩展ComplexTypeUnwrapped?真:假//真的
类型isSubtype=ComplexTypeUnwrapped扩展ComplexType?真:假//真的
所有这些都是为了明确以下几点:
有两个鉴别属性(filterType
和isFilterable
)李>
在这种情况下,不执行该操作李>
以上的组合证明是TypeScript的一个已确认的设计限制(请参阅源存储库中的和问题,这些问题导致前一个问题被提出)
但是你能做些什么呢never
解救:被禁止作为属性与拥有类型never
几乎是一样的,因此简单地更改isFilterable
属性以避免使isFilterable
成为第二个鉴别属性(为简单起见省略额外的可选属性)应该可以做到:
类型列=
(
{name:string,isFilterable:true,filterType:“选择”,选项:string[]}
{name:string,isFilterable:true,filterType:“TEXT”|“DATE”}
{name:string,isFilterable:never}|
{name:string,isFilterable:false}//允许“仅名称”大小写
)
const notFilterableAll:Column={name:'col2',isFilterable:false};
const notFilterableText:Column={name:'col2',filterType:'TEXT}//缺少属性“isFilterable”;
const notfilterableleselect:Column={name:“col2”,filterType:“SELECT”,选项:[]}//缺少属性“isFilterable”;
const notFilterableSelectMissingOpts:Column={name:“col2”,filterType:“SELECT”}//类型“选择”不可分配给类型“文本”|“日期”;
const-selectFilterOk:Column={name:'col2',isFilterable:true,filterType:“SELECT”,选项:[]}//好啊
const textFilter:Column={name:“col2”,isFilterable:true,filterType:“TEXT”}//好啊
哦,那是个好主意。你偶然发现了受歧视的工会在交叉路口的行为。如果没有人比我强,我明天就起草一份答复。这里有一个证据证明,你的想法只适用于嵌套的歧视工会:@OlegValter谢谢你的回复。我一直试图根据您上面发送的代码片段改进我的代码,但它不适合,我无法处理它。如果你能帮我办好我的案子,我会很感激的。嗯,我想我被其他事情弄得心烦意乱了,对不起-谢谢你给我回电话:(我很快就会给它一个机会。我需要先搜索一个好的参考资料-我想我看到了TS源回购协议上关于类似问题的讨论。rry,我删除了上面的一条评论,因为在过去的时间里,我忘记了你的问题不是关于嵌套的有区别的联合,而是关于对象类型与交叉点的联合。这是一个单独的问题e问题(可能与问题#9919有关,但我需要首先调查)呸-终于说到了:)这个问题是不同的,但可以解决。对于编辑和随后的回滚,我深表歉意,我有一个小实验需要运行,请不要介意-谢谢!谢谢你详尽的回答。Idea with从不
涵盖大多数情况,但仍然是{name:'col2}
TS需要是可过滤的,但不应该:/@bastej-刚刚注意到我打错了,让读者想知道我的意思是什么:)Re:{name:string}
case-是的,不幸的是,这是为解决方案付出的代价-我认为你现在不能完全解决它。至少它在团队的轨道上…@bastej-你可以在列中添加第四个工会成员
type FilterableColumn = {
isFilterable: true;
filterType: 'SELECT' | 'TEXT' | 'DATE';
options: string[];
isTopBarFilter?: boolean;
};
type NonFilterableColumn = {
isFilterable: false;
};
type Column = (NonFilterableColumn | FilterableColumn) & {
name: string;
};
type FilterableSelectColumn = {
filterType: 'SELECT';
options: string[];
};
type FilterableNonSelectColumn = {
filterType: 'TEXT' | 'DATE' | 'NUMBER';
};
type FilterableColumn = (FilterableSelectColumn | FilterableNonSelectColumn) & {
isFilterable: true;
isTopBarFilter?: boolean;
};
type NonFilterableColumn = {
isFilterable: false;
};
type Column = (FilterableColumn | NonFilterableColumn) & {
name: string;
};
// e.g
const col: Column = {
name: 'col2',
isFilterable: false,
filterType: 'SELECT', // unwanted
isTopBarFilter: false, // unwanted
options: ['option1'], // unwanted
};