TypeScript (v3.2.2) позволяет мне определить объединение интерфейсов, каждый из которых имеет уникальное строковое литеральное свойство, которое можно использовать в качестве защиты типа, например,
type Device = Laptop | Desktop | Phone;
interface Laptop {
type: 'Laptop';
countDriveBays: number;
hasTouchScreen: boolean;
}
interface Desktop {
type: 'Desktop';
countDriveBays: number;
}
interface Phone {
type: 'Phone';
hasTouchScreen: boolean;
}
function printInfo(device: Device) {
if (device.type === 'Laptop') {
// device: Laptop
console.log(
`A laptop with ${device.countDriveBays} drive bays and ${
device.hasTouchScreen ? 'a' : 'no'
} touchscreen.`,
);
} else if (device.type === 'Desktop') {
// device: Desktop
console.log(`A desktop with ${device.countDriveBays} drive bays.`);
} else {
// device: Phone
console.log(`A phone with ${device.hasTouchScreen ? 'a' : 'no'} touchscreen.`);
}
}
Я хочу написать функциюisDeviceType
в общем виде:
const isDeviceType = <T extends Device['type']>(type: T) => {
return (device: Device): device is DeviceOf<T> => device.type === type;
}
// e.g.
const isPhone = isDeviceType('Phone');
isPhone({ type: 'Phone', hasTouchScreen: true }); // true
Однако способ, которым я определил тип DeviceOf
, довольно многословен, поскольку в нем перечислены все типы внутри объединения:
type DeviceOf<Type extends Device['type']> =
Type extends Laptop['type'] ? Laptop :
Type extends Desktop['type'] ? Desktop :
Type extends Phone['type'] ? Phone :
never;
Есть ли более краткий способ определения DeviceOf
? Я пробовал это:
type DeviceOf<Type extends Device['type']> =
(infer D)['type'] extends Type ? D : never;
// TS2536: Type '"type"' cannot be used to index type 'D'.
// TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
// TS6133: 'D' is declared but its value is never read.
type DeviceOf<Type extends Device['type']> =
(infer D) extends Device
? D['type'] extends Type
? D
: never
: never;
// TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
// TS6133: 'D' is declared but its value is never read.
// TS2304: Cannot find name 'D'.
У меня сложилось впечатление, что ошибка TS1338 является ограничивающим фактором, и поэтомуневозможно определить DeviceOf
в общем виде в текущей версии TypeScript.