断言所有其余参数均未定义的类型保护

问题描述 投票:0回答:1

是否可以创建一个用户定义的类型保护,让编译器知道传递给它的所有参数都已定义?

我想做这样的事情:

  public static all(...values: unknown[]): values is object[] {
    return values.every(value => typeof(value) !== 'undefined');
  }

我想使用它,以便我可以传递一组可能未定义的参数,处理它们未定义时发生的情况,否则将它们传递给需要值未定义的方法。

可能看起来像这样:

    if (!ParamHelper.all(id, ...dateParts)) { return []; }
    const date = new Date(dateParts.join('-'));
    const result = await this.service.getData(assetId, date);

当我尝试上面的简单版本时,编译器告诉我:

类型谓词不能引用剩余参数

所以,我目前认为这是不可能完成的。但是,我想在放弃之前我应该问一下。

谢谢!

typescript typeguards
1个回答
0
投票

您可以将数组传递给函数,而不是使用其余参数:

public static all(values: unknown[]): values is object[] {
    return values.every(value => typeof(value) !== 'undefined');
}

但是,该代码在技术上是不正确的,因为您断言这些值是对象,而您除了它们未定义之外一无所知。您应该检查 typeof 是否等于“object”,或者更正返回类型:

public static all(values: unknown[]): values is (string|number|object|symbol|boolean)[] {
    return values.every(value => value !== null && typeof value !== 'undefined');
  }
}

请注意,

typeof null === "object"
不幸的是,这两种比较都不会消除空值。我冒昧地在上面添加了一个空检查。

现在,如果您这样使用代码:

if (!ParamHelper.all([id, ...dateParts])) { return []}
const date = new Date(dateParts.join('-'));

然后您将鼠标悬停在第二行中的 dateParts 上,您将看到 typeguard 不起作用。令人沮丧的是

dateParts
仍然未定义。但很容易理解为什么,它可能会帮助您理解为什么它不适用于其余参数:

const checked = [id, ...dateParts];
if (!ParamHelper.all(checked)) return [];
const checkedDateParts = checked.slice(1);
const date = new Date(checkedDateParts.join('-'));

在这里,如果您将鼠标悬停在checked或checkedDateParts上,您会注意到它们是预期的类型。在上面的情况以及剩余参数的情况下,正在确定类型的数组在函数调用结束时被丢弃。 Typescript 还不够智能,无法将包含数组的类型追溯传递到其组成部分。鉴于这种逻辑可能是有条件的或迭代的,因此有理由期望它永远无法做到这一点。

在上面的示例中,我们保留了对数组的引用,因此也保留了类型。因此它有效。

我个人认为在这里使用类型保护是过度设计的。鉴于上下文是日期,您在评论中提供的代码:

if (!id || !day || !month || !year) { return; }

更清晰、更短、更易于维护。

如果你必须使用类型保护,我会选择类似的东西:

if (!id || !ParamHelper.all(dateParts)) { return }
const date = new Date(dateParts.join('-'));

游乐场链接

© www.soinside.com 2019 - 2024. All rights reserved.