TypeScript: перегрузка функции в зависимости от типа класса параметра - PullRequest
0 голосов
/ 30 января 2019

Можно ли применить перегрузки функции TypeScript на основе типа класса параметра?

Я понимаю, что "классы" будут скомпилированы в простые функции в выводе, но я надеюсь, чтозаставить проверку типа работать в зависимости от типа ввода.

Цель состоит в том, чтобы создать функцию send() для связи с сервером, которая возвращает типизированный ответ на основе типа запроса.Тем не менее, TypeScript всегда выбирает первую перегрузку независимо от типа передаваемого класса.

interface IRequest {
  getBody(): object;
}

class UserRequest implements IRequest {
  getBody() {
    return { type: 'user', id: 7 };
  }
}

class CompanyRequest implements IRequest {
  getBody() {
    return { type: 'company', id: 42 };
  }
}

interface IUserResponse {
  userName: string;
}

interface ICompanyResponse {
  companyName: string;
}

function send(request: UserRequest): Promise<IUserResponse>;
function send(request: CompanyRequest): Promise<ICompanyResponse>;
async function send(request: IRequest): Promise<any> {
  const response = await fetch('https://example.com/service', {
    body: request.getBody(),
  });
  return response.json();
}

async function test() {

  // Works
  const userResponse = await send(new UserRequest());
  userResponse.userName;

  // Error: [ts] Property 'companyName' does not exist on type 'IUserResponse'. [2339]
  const companyResponse = await send(new CompanyRequest());
  companyResponse.companyName;

}

Смена порядка объявленных перегрузок устраняет проблему (тип возвращаемого значения всегда будет CompanyRequest вместоUserRequest).

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Похоже, ваша проблема в том, что компилятор считал, что и UserRequest, и CompanyRequest структурно совместимы, то есть, по сути, они одного типа.Поэтому всегда выбирается первая перегрузка, и случаются плохие вещиСамый простой способ избежать этого - добавить свойства хотя бы к одному из типов, чтобы компилятор распознал их как отдельные типы .Вот один из возможных способов:

class UserRequest implements IRequest {
  getBody() {
    return { type: 'user', id: 7 };
  }
  readonly className = "UserRequest"
}

class CompanyRequest implements IRequest {
  getBody() {
    return { type: 'company', id: 42 };
  }
  readonly className = "CompanyRequest"
}

В этом случае свойство readonly className получает несколько строковых значений, которые различаются.Надеюсь, это поможет.Удачи!

0 голосов
/ 30 января 2019

Как насчет общего подхода?

async function send<T>(request: T): Promise<T> {
    const response = await fetch('https://example.com/service', {
        body: request.getBody(),
    });
    return response.json();
}
...