bas*_*tej 5 types discriminated-union typescript
#1我有一个对象列的类型。列可以是可过滤的或不可过滤的,如果isFilterable是,true则类型Column应要求:filterType,isTopBarFilter?和options(但仅当filterType是'SELECT'- #2 时)。
type Column = {
name: string;
isFilterable: boolean; // passing here false should be equal with not passing the property at all (if possible)
// below properties should exist in type only if isFilterable = true
filterType: 'SELECT' | 'TEXT' | 'DATE';
options: string[]; // this property should exist in type only if filterType = 'SELECT'
isTopBarFilter?: boolean;
};
Run Code Online (Sandbox Code Playgroud)
我使用类型联合来做这种类型,它几乎可以正常工作
type FilterableColumn = {
isFilterable: true;
filterType: 'SELECT' | 'TEXT' | 'DATE';
options: string[];
isTopBarFilter?: boolean;
};
type NonFilterableColumn = {
isFilterable: false;
};
type Column = (NonFilterableColumn | FilterableColumn) & {
name: string;
};
Run Code Online (Sandbox Code Playgroud)
但:
Column应要求options只有当filterType是'SELECT'。我试图用类型联合来做到这一点,但它变得很奇怪: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
};
Run Code Online (Sandbox Code Playgroud)
如果我设置isFilterable为 false,TS 不会建议不需要的属性(很好),但如果我传递这些不需要的道具也不会显示错误(不好)
isFilterable即使它是false,正如我上面提到的,我只想通过它true有没有办法改进我的解决方案(或其他解决方案)以实现我在开头(#1)描述的内容?
好吧,经过几个晚上我设法做到了,我有两个解决方案:
1.
type FilterableColumn = {
isFilterable: true;
isTopBarFilter?: boolean;
} & (
| {
filterType: 'SELECT';
options: string[];
}
| {
filterType: 'TEXT' | 'DATE';
});
type NonFilterableColumn = {
isFilterable?: undefined; // same result with never
filterType?: undefined; // same result with never
};
type ColumnBaseFields = {
name: string;
};
type Column = (FilterableColumn | NonFilterableColumn) & ColumnBaseFields;
const column: Column = {
name: 'someName',
isFilterable: true,
filterType: 'SELECT',
options: ['option'],
};
Run Code Online (Sandbox Code Playgroud)
它按照我想要的方式工作,在这些情况下出现打字稿错误,但错误描述不准确。我注意到 TypeScript 在同一嵌套级别上的许多联合上工作得很奇怪
因此,我使用嵌套过滤器选项编写了第二个解决方案
2.
type FilterSettings = (
| {
filterType: 'SELECT';
options: string[];
}
| {
filterType: 'TEXT';
}) & {
isTopBarFilter?: boolean;
};
type FilterableColumn = {
isFilterable: true;
filterSettings: FilterSettings;
};
type NonFilterableColumn = {
isFilterable?: undefined; // same result with never
};
type ColumnBaseFields = {
name: string;
};
type Column = (FilterableColumn | NonFilterableColumn) & ColumnBaseFields;
const column: Column = {
name: 'someName',
isFilterable: true,
filterSettings: {
filterType: 'SELECT',
options: ['option']
}
};
Run Code Online (Sandbox Code Playgroud)
工作正常,打字稿准确地告诉我们何时遗漏了某些键以及何时不需要某些键。
我希望这对某人有帮助