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

时间:2021-06-15 15:17:31

标签: typescript typescript4.0

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

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

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

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

考虑这个例子:

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'
}

返回以下错误:

<块引用>

“IVehicle”类型的参数不可分配给“IVehicleNonNullVin”类型的参数。
属性“vin”的类型不兼容。
输入'字符串| null' 不可分配给类型 'string'。
类型 'null' 不能分配给类型 'string'。

即使我肯定,这里的属性也不能为空。

:我如何根据代码流中的类型检查让 TS 相信现有模型符合类型?

Demo in TS Playground


解决方法

作为一种解决方法,我可以强制转换类型(但忽略了现有的类型安全):

needsVin(myVehicle as IVehicleNonNullVin);

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

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

1 个答案:

答案 0 :(得分:2)

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

export function useParams<T extends string>(
  expected: T[]
): { [key in T as NonOptional<T>]: string } {
  // ... our custom implementation
  return null as any;
}

type NonOptional<T extends string> = T extends `?${infer Inner}` ? Inner : T;

// Should produce type { a: string; b: string | undefined }
const result = useParams(['a', '?b']);
<块引用>

如果原始类型兼容,TypeScript 会缩小该变量到该特定类型。

Demo in TS Fiddle