I am facing a challenge where I need to merge two separate Typescript methods into one with the same name getDevice
. The first method only requires a number input to return a Device
, or null
if no device is found:
protected getDevice(deviceId: number): Device | null {
const device = this.devicesService.getDevice(deviceId);
if (device == null)
console.warn(`Failed to retrieve device #${deviceId}.`);
return device;
}
The second method takes two arguments. The first argument can be either a number (similar to the previous method) or a Device
(the result of the previous method):
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 retrieve the device #${deviceOrId}.`);
return null;
}
return new deviceType(device);
}
The combined method would look something like this:
protected getDevice<<T extends DeviceType>(
deviceOrId: Device | number,
deviceType: (new (device: Device) => T) | null = null,
): Device | T | null {
let device: Device | null = null;
// If deviceOrId is a number
if (typeof deviceOrId === 'number') {
device = this.devicesService.getDevice(deviceOrId);
if (device == null) {
console.warn(`Failed to retrieve device #${deviceOrId}.`);
return null;
}
if (deviceType == null) return device;
}
// Implementing getDeviceAs functionality
return new deviceType(device);
}
The tricky part is defining the proper types for the entire function:
- The return type depends on the type of the
deviceOrId
argument:- If
deviceOrId
is aDevice
, then the result should definitely beT | null
- If
deviceOrId
is anumber
, the result could beDevice | T | null
- If
- The return type and
deviceOrId
are influenced by thedeviceType
argument:- If
deviceType
isnull
, thendeviceOrId
must be of typenumber
and the return type isDevice | null
- If
deviceType
is of type(new (device: Device) => T)
, then the return type must beT | null
- If
Is achieving this kind of complexity possible in Typescript? If so, how can it be done? Perhaps utilizing some function overloading techniques?