Typescript接口-使一个属性的类型取决于另一个属性的类型

时间:2020-07-30 13:15:47

标签: typescript

我有一些看起来像这样的接口:

export enum SortValueType {
  String = 'string',
  Number = 'number',
  Date = 'date',
}


export interface SortConfig {
  key: string;
  direction: SortDirection;
  type: SortValueType;
  options?: {
    sortBy?: 'year' | 'day';
  };
}

我想扩展它,以便options.sortBy的可能类型应取决于type。我正在根据type创建迭代对象,因此不可能创建typestring并且options.sortBy的值为year的对象。 / p>

这是getIteratee函数:

 private getIteratee(config: SortConfig) {
    if (config.type === SortValueType.String) {
      return item => _lowerCase(item[config.key]);
    }

    if (config.type === SortValueType.Date) {
      const sortBy = _get(config, 'options.sortBy') as 'year' | 'day';

      if (!!sortBy && sortBy === 'year') {
        return item =>
          !!item[config.key]
            ? new Date(item[config.key]).getFullYear()
            : undefined;
      }

      if (!!sortBy && sortBy === 'day') {
        return item =>
          !!item[config.key]
            ? new Date(item[config.key].toJSON().split('T')[0])
            : undefined;
      }
    }

    return config.key;
  }

我也愿意接受更通用的解决方案

1 个答案:

答案 0 :(得分:2)

我认为您想要这样的东西:

export enum SortValueType {
  String = 'string',
  Number = 'number',
  Date = 'date',
}

type SortDirection = string;

export interface SortConfig<T extends SortValueType> {
  key: string;
  direction: SortDirection;
  type: T;
  options:
    T extends SortValueType.Date
      ? { sortBy: 'year' | 'day'; }
      : { sortBy?: undefined };
}
// OK:
let dateConfig: SortConfig<SortValueType.Date> = {
  key: "key",
  direction: "left",
  type: SortValueType.Date,
  options: { sortBy: 'year' }
}

// Not OK:
let numberConfig: SortConfig<SortValueType.Number> = {
  key: "key",
  direction: "left",
  type: SortValueType.Number,
  options: { sortBy: 'year' }
}

Playground link

sortBy?: undefined是必需的,因为TypeScript在默认情况下不会阻止额外的属性。如果您仅使用{},则{ sortBy: 'year' }实际上是有效的,因为它可以分配给{}

您可以从此处调整options的确切类型,具体取决于您希望每种类型的选项起作用的程度。

要使getIteratee正常工作,您需要将参数更改为SortConfig<any>,定义一个类型保护,并使用它来缩小每种情况的类型。像这样:

function isConfigType<T extends SortValueType>(
    config: SortConfig<any>, type: T
): config is SortConfig<T> {
  return config.type === type;
}

function getIteratee(config: SortConfig<any>) {
    if (isConfigType(config, SortValueType.String)) {
        // The type of 'config' here is SortConfig<SortValueType.String>;
    } ...
}