Условный тип в зависимости от значения аргументов функции - PullRequest
0 голосов
/ 07 августа 2020

Я пытаюсь объединить 2 отдельных метода Typescript в один с тем же именем getDevice. Первая функция требует только числа, чтобы вернуть Device или null в случае отсутствия устройства:

protected getDevice(deviceId: number): Device | null {
  const device = this.devicesService.getDevice(deviceId);
  if (device == null)
    console.warn(`Failed to get the device #${deviceId}.`);
  return device;
}

Вторая функция принимает 2 аргумента. Первый - это число (как в предыдущей функции) или Device (результат предыдущей функции):

protected getDeviceAs<T extends DeviceType>(
  deviceOrId: Device | number,
  deviceType: (new (device: Device) => T),
): T | null {
  const device = typeof deviceOrId === 'number'
    ? this.devicesService.getDevice(deviceOrId)
    : deviceOrId as Device;
  if (device == null) {
    console.warn(`Failed to get the device #${deviceOrId}.`);
    return null;
  }
  return new deviceType(device);
}

Результат объединения двух методов будет примерно таким:

protected getDevice<T extends DeviceType>(
  deviceOrId: Device | number,
  deviceType: (new (device: Device) => T) | null = null,
): Device | T | null {
  let device: Device | null = null;
  // In case deviceOrId is a number
  if (typeof deviceOrId === 'number') {
    device = this.devicesService.getDevice(deviceOrId);
    if (device == null) {
      console.warn(`Failed to get the device #${deviceOrId}.`);
      return null;
    }
    if (deviceType == null) return device;
  }

  // getDeviceAs functionality
  return new deviceType(device);
}

Проблема в том, что я не могу понять, как правильно набрать всю функцию:

  • тип возврата зависит от типа аргумента deviceOrId:
    • if deviceOrId - это Device, тогда результат обязательно должен быть T | null
    • , если deviceOrId - number, тогда это может быть Device | T | null
  • тип возврата и deviceOrId зависят от аргумента deviceType:
    • если deviceType - это null, то deviceOrId должен иметь тип number и тип возвращаемого значения Device | null
    • если deviceType - это (new (device: Device) => T), то тип возврата должен быть T | null

Возможно ли это вообще в Typescript? Если да, то как? Может быть, с какими-то уловками с перегрузкой функций?

1 Ответ

1 голос
/ 07 августа 2020

Есть простое решение проблемы. Вы можете перегружать функции в машинописном тексте ( документация ). Сначала вы объявляете функциональные подписи. В случае этого вопроса это будет:

protected getDevice(deviceId: number): Device | null;
protected getDevice<T extends DeviceType>(
  deviceOrId: Device | number,
  deviceType: (new (device: Device) => T),
): T | null;

Затем вы пишете реализацию функции, которая будет обрабатывать logi c. Эта сигнатура функции реализации не будет рассматриваться как еще одна перегрузка. Полный код:

// Overload 1:
protected getDevice(deviceId: number): Device | null;
// Overload 2:
protected getDevice<T extends DeviceType>(
  deviceOrId: Device | number,
  deviceType: (new (device: Device) => T),
): T | null;
// Implementation:
protected getDevice<T extends DeviceType>(
  deviceOrId: Device | number,
  deviceType: (new (device: Device) => T) | null = null,
): Device | T | null {
  let device: Device | null = null;
  if (typeof deviceOrId === 'number') {
    device = this.devicesService.getDevice(deviceOrId);
    if (device == null) {
      console.warn(`Failed to get the device #${deviceOrId}.`);
      return null;
    }
    if (deviceType == null) return device;
  }
  return new deviceType(device);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...