打字稿可以推断出一个参数已经过验证吗? [英] Can typescript infer that an argument has been validated?

查看:23
本文介绍了打字稿可以推断出一个参数已经过验证吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我仍在学习 Typescript 和 Javascript,所以如果我遗漏了什么,请见谅.

I'm still learning Typescript and Javascript so please excuse me if I am missing something.

问题如下:

目前,如果在调用 this.defined(email) 时未定义电子邮件,VSCode 不会推断我抛出错误.这是因为 validateEmail() 接受一个 string? 并且不会编译,因为它认为它仍然可以接收未定义的值(至少是我的推论).有没有办法告诉编译器这没问题?还是我遗漏了什么?

Currently VSCode does not infer that I throw an error if email is undefined when calling this.defined(email). This is due to validateEmail() accepting a string? and will not compile because it thinks it could still receive an undefined value (is my deduction at least). Is there a way to tell the compiler this is ok? or am I missing something?

我想从其他类调用 Validate.validateEmail() 并且这些类中也会出现问题.

I would like to call Validate.validateEmail() from other classes and the problem arises in those classes as well.

export default class Validate {
    static validateEmail(email?: string) {
        // TODO: Test this regex properly.
        const emailRegex = new RegExp('^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$')

        this.defined(email);
        this.notEmpty(email);

        if (!emailRegex.test(email)) {
            throw new SyntaxError("The email entered is not valid");
        }
    }

    static defined(text?: string) {
        if (!text) {
            throw new SyntaxError("The text recieved was not defined.");
        }
    }

    static notEmpty(text: string) {
        if (text.length < 1) {
            throw new SyntaxError("The text entered is empty.");
        }
    }
}

推荐答案

编译器有时可以通过 分析控制流.在下面的代码块中,编译器知道如果控制流到达 this.notEmpty() 调用,则 email 不能是 undefined,并且因此没有错误:

The compiler can sometimes recognize that a variable is of a type narrower than its annotated or inferred type at certain points in the code, by analyzing the control flow. In the following code block, the compiler understands that email cannot be undefined if the flow of control reaches the this.notEmpty() call, and thus there is no error:

if (!email) {
    throw new SyntaxError("The text received was not defined.");
}

this.notEmpty(email); // okay

<小时>

不过,正如您所发现的,简单地重构代码以在不同的函数中进行检查是行不通的.在执行控制流分析时,编译器通常不会遵循控制流进入函数和方法.这是一个权衡(有关详细信息,请参阅 GitHub 中的 Microsoft/TypeScript#9998):编译器通过分析所有可能的函数调用的可能控制流路径来模拟在所有可能输入上运行的程序是不可行的,因此它必须在某处使用启发式方法;在这种情况下,启发式通常是假设函数调用对变量类型没有影响".因此,对 this.defined(email) 的调用对编译器所看到的 email 类型没有影响,因此它会抱怨 this.notEmpty(电子邮件).


As you've discovered, though, simply refactoring the code to make the check happen in a different function does not work. The compiler generally does not follow control flow into functions and methods when performing control flow analysis. This is a tradeoff (see Microsoft/TypeScript#9998 in GitHub for more info): it's not feasible for the compiler to simulate the program running on all possible inputs, by analyzing the possible control flow paths through all possible function calls, so it has to use a heuristic somewhere; in this case, the heuristic is generally "assume function calls have no impact on variable types". Therefore the call to this.defined(email) has no impact on the type of email as seen by the compiler, and thus it complains about this.notEmpty(email).

幸运的是,引入了TypeScript 3.7"断言函数";你可以给一个函数一个特殊的返回类型,它告诉编译器传递给函数的变量将被函数缩小,它会使用它作为其控制流分析的一部分.虽然编译器本身不会推断这样的函数签名,但至少现在您可以手动注释 defined() 对其参数的某些断言:

Luckily, TypeScript 3.7 introduced "assertion functions"; you can give a function a special return type that tells the compiler that a variable passed to the function will be narrowed by the function, and it will use this as part of its control flow analysis. While the compiler doesn't infer such function signatures itself, at least now you can manually annotate that defined() asserts something about its argument:

static defined(text?: string): asserts text {
    if (!text) {
        throw new SyntaxError("The text recieved was not defined.");
    }
}

defined() 的返回类型是 asserts text,这意味着如果 defined() 返回.这修复了您的原始示例:

The return type of defined() is asserts text, which means that text will be verified as truthy if defined() returns. And this fixes your original example:

this.defined(email);
this.notEmpty(email); // okay now!

看起来不错.好的,希望有帮助;祝你好运!

Looks good. Okay, hope that helps; good luck!

游乐场链接到代码

这篇关于打字稿可以推断出一个参数已经过验证吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆