条件类型取决于函数参数的值

时间:2020-08-07 03:04:54

标签: typescript types

我正在尝试将2个单独的Typescript方法合并为一个具有相同名称getDevice的方法。如果没有设备,第一个函数只需要一个数字即可返回Devicenull

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参数类型:
    • 如果deviceOrIdDevice,则肯定结果必须是T | null
    • 如果deviceOrIdnumber,则它可能是Device | T | null
  • 返回类型和deviceOrId取决于deviceType参数:
    • 如果deviceTypenull,则deviceOrId的类型必须为number,返回类型为Device | null
    • 如果deviceType(new (device: Device) => T),则返回类型必须为T | null

在打字稿中甚至有可能吗?如果是,怎么办?也许有一些函数重载技巧?

1 个答案:

答案 0 :(得分:1)

有一个简单的解决方案。您可以在打字稿(documentation)中重载函数。首先,您声明函数签名。如果出现这个问题,它将是:

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

然后,编写将处理逻辑的函数实现。该实现功能签名不会被视为另一个重载。完整代码:

// 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);
}
相关问题