添加基于另一个属性的额外类型属性

bas*_*tej 5 types discriminated-union typescript

#1我有一个对象列的类型。列可以是可过滤的或不可过滤的,如果isFilterable是,true则类型Column应要求:filterTypeisTopBarFilter?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)

但:

  1. 正如我前面提到的(#2Column应要求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 不会建议不需要的属性(很好),但如果我传递这些不需要的道具也不会显示错误(不好)

  1. 我的解决方案也强制通过,isFilterable即使它是false,正如我上面提到的,我只想通过它true

有没有办法改进我的解决方案(或其他解决方案)以实现我在开头(#1)描述的内容?

bas*_*tej 0

好吧,经过几个晚上我设法做到了,我有两个解决方案:

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)

操场

工作正常,打字稿准确地告诉我们何时遗漏了某些键以及何时不需要某些键。

我希望这对某人有帮助