Typescript 接口 - 使一个属性的类型依赖于另一属性的类型

mch*_*l18 2 typescript

我有一些接口,如下所示:

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


export interface SortConfig {
  key: string;
  direction: SortDirection;
  type: SortValueType;
  options?: {
    sortBy?: 'year' | 'day';
  };
}
Run Code Online (Sandbox Code Playgroud)

我希望能够扩展它,以便可能的类型options.sortBy应该依赖于type. 我正在创建迭代器,type因此它不应该创建一个对象,其中typeisstringoptions.sortBy值为year

这是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;
  }
Run Code Online (Sandbox Code Playgroud)

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

Tim*_*rry 5

我想你想要这样的东西:

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' }
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接

sortBy?: undefined是必需的,因为默认情况下 TypeScript 不会阻止额外的属性。如果您只是使用{}then{ 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>;
    } ...
}
Run Code Online (Sandbox Code Playgroud)