如何更好地处理Partial <T>接口

时间:2019-11-27 17:49:38

标签: typescript

在以下情况下,我不想信任不受信任的对象,并希望在对每个字段进行操作之前先检查每个字段是否为真。但是,使用Partial泛型时,它不会推断在尝试将字段传递给函数时该字段不是未定义的。有更好的方法来解决这个问题吗?

7855

错误:

export interface IFoo {
  id: number;
  value: string;
}

export function DoBar(obj: IFoo) {
  // do stuff
  return;
}

const untrustedObj: Partial<IFoo> = { id: 1, value: 'test' };

if (untrustedObj.id && untrustedObj.value) {
  DoBar(untrustedObj); // Error
}

2 个答案:

答案 0 :(得分:4)

您可以使用is来写type guard function来缩小对象的类型:

function hasKey<T, K extends keyof T>(obj: Partial<T>, key: K):
    obj is Partial<T> & { [k in K]: T[k] }
{
    return Object.prototype.hasOwnProperty.call(obj, key);
}

用法:

if(hasKey(untrustedObj, 'id') && hasKey(untrustedObj, 'value')) {
  doBar(untrustedObj); // no type error
}

我使用Object.prototype.hasOwnProperty作为测试此问题的更通用的解决方案,因为您可能想检查布尔属性是否存在(而不是检查其是否为真)。

Playground Link

答案 1 :(得分:2)

请参阅microsoft/TypeScript#28882,了解为什么它不起作用。如果对象不是可区分联合类型,则检查其属性不会缩小对象本身的类型。您可能需要user defined type guard或其他一些重构方法才能完成这项工作。

一种这样的重构是将属性保存到它们自己的变量中,因为如果您检查它们,TypeScript的编译器将缩小变量的类型:

const uId = untrustedObj.id;
const uValue = untrustedObj.value;
if (typeof uId !== "undefined" && typeof uValue !== "undefined") {
    DoBar({ id: uId, value: uValue }); // okay
}

我对类型保护功能的建议如下:

function definedProp<T, K extends keyof T>(
    obj: T, ...props: K[]
): obj is T & Required<Pick<T, K>> {
    return props.every(k => typeof obj[k] !== "undefined");
}

这将检查objprops数组中的每个键定义一个值,如果是,则它将缩小传入的obj。然后像这样使用它:

if (definedProp(untrustedObj, "id", "value")) {
    DoBar(untrustedObj); // okay
}

好的,希望能有所帮助;祝你好运!

Link to code