将具有可为空字符串 属性 的接口转换为字符串 属性

Convert interface with nullable string property to string property

我有以下两个接口,一个允许可空 vin,另一个不允许:

interface IVehicle {
    vin: string | null;
    model: string;
}

interface IVehicleNonNullVin {
    vin: string;
    model: string;
}

我希望能够在我能够推断 vin 不是 null 的执行路径中将模型从 IVehicle 转换为 IVehicleNonNullVin

考虑这个例子:

const myVehicle: IVehicle = {
    vin: 'abc123',
    model: 'm3'
};

const needsVin = (_: IVehicleNonNullVin) => false;

if (myVehicle.vin === null) {
    throw new Error('null');
} else {
    needsVin(myVehicle);
 // ~~~~~~~~~~~~~~~~~~~ 'IVehicle' is not assignable to 'IVehicleNonNullVin'
}

其中returns出现以下错误:

Argument of type 'IVehicle' is not assignable to parameter of type 'IVehicleNonNullVin'.
Types of property 'vin' are incompatible.
Type 'string | null' is not assignable to type 'string'.
Type 'null' is not assignable to type 'string'.

即使我 阳性 属性 在这里也不可为空。

Q: 如何让TS相信现有模型符合代码流中基于类型检查的类型?

Demo in TS Playground


解决方法

作为变通方法,我可以转换类型(但这会忽略现有的类型安全):

needsVin(myVehicle as IVehicleNonNullVin);

构建一个新模型(但这不能很好地扩展大量属性):

const nonNullVehicle: IVehicleNonNullVin = {
    model: myVehicle.model,
    vin: myVehicle.vin
}
needsVin(nonNullVehicle);

您可以使用 type predicate 来定义用户定义的类型保护,如下所示:

const isNonNullVin = (vehicle: IVehicle): vehicle is IVehicleNonNullVin =>{
    return vehicle.vin !== null
}

if (!isNonNullVin(myVehicle)) {
    throw new Error('null');
} else {
    needsVin(myVehicle);
}

TypeScript will narrow that variable to that specific type if the original type is compatible.

Demo in TS Fiddle