网站搜索

TypeScript - 在什么时候会需要使用 'is' 谓词,而不是使用 'in' 操作符?


根据 TypeScript 文档,我们可以使用类型保护来区分不同的类型。

文档给出了使用 is 谓词和使用 in 操作符的示例。

是 谓词:

function isFish(pet: Fish | Bird): pet is Fish {
    return (pet as Fish).swim !== undefined;
}

if (isFish(pet)) {
    pet.swim();
}
else {
    pet.fly();
}

in 操作符:

function move(pet: Fish | Bird) {
    if ("swim" in pet) {
        return pet.swim();
    }
    return pet.fly();
}

in 运算符看起来要简洁得多,也更简单——尽管也许将类型区分明确地提取到一个函数中是有帮助的,而且从长期来看更易于维护。

是否存在某些情况下 is 谓词可以区分类型,而 in 运算符不能?

答案 #1

in 操作符只是缩小变量类型的一种方法。你可以使用任何你喜欢的检查来编写类型保护:

type JSONPrimitive = number | string | boolean | null;

function isJsonPrimitive(x: any): x is JSONPrimitive {
    return x === null
        || typeof x === 'number'
        || typeof x === 'string'
        || typeof x === 'boolean';
}

或者:

interface TreeNode {
    value: number;
    left: TreeNode | null;
    right: TreeNode | null;
}
type InternalNode = TreeNode & ({ left: TreeNode } | { right: TreeNode });

function isInternalNode(node: TreeNode): node is InternalNode {
    return node.left !== null || node.right !== null;
}

这两个例子都不能用 in 运算符进行等效重写。

也就是说,用户定义的类型保护类似于类型断言,因为 TypeScript 不会检查它们的正确性。所以你可以在类型保护的实现中使用任何你喜欢的逻辑;甚至无条件的 return true; 也是允许的。