В Typescript вынудите параметр общего типа удовлетворять ограничениям типа на основе определений перегрузки функций - PullRequest
0 голосов
/ 19 апреля 2019

Необходимый скелет кода для упрощения задачи приведен ниже.В принципе, могут быть различные типы Source объектов.Для простоты в коде ниже показаны два типа источников: DirectSource и IndirectSource.Функция sourceAdapter() принимает Source и другие вспомогательные параметры.

В примере: если параметр key отсутствует, Source должно быть DirectSource;если key является одиночным строковым значением, то Source должно быть IndirectSource, и в обоих случаях код выполняет необходимые корректировки и возвращает объект DirectSource.Если key является массивом, предполагается, что Source будет IndirectSource, что также является возвращаемым значением функции.


type KeyMap<T> = { [key in keyof T]: number };

type DirectSource = {
  value: number;
  otherFieldsAndMethods: any;
};

type IndirectSource<T extends object> = {
  kvMap: KeyMap<T>;
  otherFieldsAndMethods: any;
};

type Source<T extends number | object> = T extends object ? IndirectSource<T> : DirectSource;

// overloads
function sourceAdapter(src: Source<number>): DirectSource;
function sourceAdapter<T extends object>(src: Source<T>, key: keyof T): DirectSource;
function sourceAdapter<T extends object>(src: Source<T>, key: (keyof T)[]): IndirectSource<T>;

function sourceAdapter<T extends number | object>(
  src: Source<T>,
  key?: keyof T | (keyof T)[]
): T extends object ? IndirectSource<T> : DirectSource {

  if (key) { // According to function overloads Source must be an IndirectSource
    if (key instanceof Array) { // Config and return IndirectSource
      const kvMap = key.reduce((ac, s) => {
        ac[s] = (src as any).kvMap[s];
        return ac;
      }, {} as any);

      // ******Error here:
      // Type 'T' does not satisfy the constraint 'object'.
      let ret: IndirectSource<T> = {
        kvMap,
        otherFieldsAndMethods: src.otherFieldsAndMethods
      };
      return ret;
    } else { // Config and return DirectSource
      let directSource = {
        otherFieldsAndMethods: src.otherFieldsAndMethods,
        value: (src as IndirectSource<any>).kvMap[key],
      };
      return directSource; // ******Error here: assignability
    }
  } else { // Source is a DirectSource, simply return the src.
    return src;
  }
}

Строки, в которых возникают ошибки, представляют собойотмечены звездами. Это ссылка на игровую площадку.

1 Ответ

1 голос
/ 19 апреля 2019

Самый простой и понятный способ - просто заменить ReturnType на объединение.Наслаждаться. Ссылка на игровую площадку

type KeyMap<T> = { [key in keyof T]: number };

type DirectSource = {
  value: number;
  otherFieldsAndMethods: any;
};

type IndirectSource<T extends object> = {
  kvMap: KeyMap<T>;
  otherFieldsAndMethods: any;
};

type Source<T extends number | object> = T extends object ? IndirectSource<T> : DirectSource;

// overloads
function sourceAdapter(src: Source<number>): DirectSource;
function sourceAdapter<T extends object>(src: Source<T>, key: keyof T): DirectSource;
function sourceAdapter<T extends object>(src: Source<T>, key: (keyof T)[]): IndirectSource<T>;
function sourceAdapter<T extends object>(
  src: Source<T>,
  key?: keyof T | (keyof T)[]
): IndirectSource<T> | DirectSource {

  if (key) { // According to function overloads Source must be an IndirectSource
    if (key instanceof Array) { // Config and return IndirectSource
      const kvMap = key.reduce((ac, s) => {
        ac[s] = (src as any).kvMap[s];
        return ac;
      }, {} as any);

      // Error here:
      // Type 'T' does not satisfy the constraint 'object'.
      let ret: IndirectSource<T> = {
        kvMap,
        otherFieldsAndMethods: src.otherFieldsAndMethods
      };
      return ret as IndirectSource<T>;
    } else { // Config and return DirectSource
      let directSource = {
        otherFieldsAndMethods: src.otherFieldsAndMethods,
        value: (src as IndirectSource<any>).kvMap[key],
      };
      return directSource; // Error here: assignability
    }
  } else { // Source is a DirectSource, simply return the src.
    return src;
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...