简体   繁体   English

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

[英]Typescript Interface - make type of one property dependent of type of another property

I have some Interfaces which look like this:我有一些看起来像这样的接口:

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


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

I would like to make it possible to extend this so that the possible types of options.sortBy should be dependent on the type .我想让扩展它成为可能,以便options.sortBy的可能类型应该取决于type I am creating iteratees depending on type so it should not be possible to create an Object where type is string and options.sortBy has a value of year .我正在根据type创建迭代器,因此应该无法创建typestringoptions.sortBy值为year的 Object 。

This is the getIteratee function:这是getIteratee function:

 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;
  }

I am also open to more generic solutions我也对更通用的解决方案持开放态度

I think you want something like this:我想你想要这样的东西:

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 游乐场链接

The sortBy?: undefined is required, because TypeScript doesn't block extra properties by default. sortBy?: undefined是必需的,因为默认情况下 TypeScript 不会阻止额外的属性。 If you just use {} then { sortBy: 'year' } is actually valid, as it is assignable to {} .如果您只使用{} ,那么{ sortBy: 'year' }实际上是有效的,因为它可以分配给{}

You can tweak the exact type of options from there, depending on how exactly you want each type's options to work.您可以从那里调整options的确切类型,具体取决于您希望每种类型的选项如何工作。

To make getIteratee work nicely, you'll want to change the parameter to SortConfig<any> , define a type guard, and use that to narrow down the type for each case.为了使 getIteratee 正常工作,您需要将参数更改为SortConfig<any> ,定义类型保护,并使用它来缩小每种情况的类型。 Like so:像这样:

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>;
    } ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM