Typescript 类断言类型保护 [英] Typescript assert-like type guard

查看:37
本文介绍了Typescript 类断言类型保护的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是否可以通过never返回的函数调用限制类型而没有if,例如undefined,如assert> 在打字稿中?

Is this possible to have types restricted without if by function calls that never return for e.g undefined like assert in Typescript?

示例代码:

interface Foo { bar(): void }
function getFoo(): Foo | undefined { }

function test() {
    const foo = someService.getFoo();
    assert(foo);
    if (!foo) { // now mandatory because without this foo may be still undefined even if assert protects us from this
        return;
    }
    foo.bar(); // , here foo may be undefined
}

我希望能够以这样的方式编写 assert,这样我就可以跳过以下 if (!foo) 子句并拥有 foo类型限制为纯 Foo.

I would like to be able to write assert in such way that i can skip following if (!foo) clause and have foo type restricted to plain Foo.

这在 Typescript 中可行吗?

Is this possible in Typescript?

我已经尝试使用 never 为抛出的类型添加重载:

I've tried adding overloads with never for types that throw:

function assertGuard(v: undefined | null | '' | 0 | false): never;
function assertGuard(v: any): void; // i'm not sure which one is  captured by TS typesystem here

function assertGuard<T>(v: T | undefined) {
    if (v === undefined || v === null || v === '' || v === 0 || v === false) {
         throw new AssertionError({message: 'foo'})
    }
}

这个可以编译,但是对 assertGuard(foo) 的调用不能识别 undefined 它将返回 never 所以不会将 foo 限制为 Foo.

This one compiles, but call to assertGuard(foo) doesn't recognize that for undefined it will return never so doesn't restrict foo to Foo.

我找到了可能的解决方法,但我认为经典的 assert 是一种更简洁的方法:

I've found possible workarounds but i consider classical assert a cleaner approach:

function assertResultDefined<T>(v: T|undefined): T | never {
    if (v === undefined) {
        throw new Error('foo');
    }
    return v;
}
function die(): never { throw new Error('value expected)}

const foo = assertResultDefined(getFoo()) // foo is Foo, undefined is erased
const foo = getFoo() || die();
    // undefined is erased from foo
    / CONS: doesn't play well with types that interpolate to `false` like 0, ''

推荐答案

Typescript 3.7 添加了 断言控制流量分析.

Typescript 3.7 adds assertions in control flow analysis.

asserts 返回类型谓词表示函数仅在断言成立时返回,否则会引发异常

An asserts return type predicate indicates that the function returns only when the assertion holds and otherwise throws an exception

不再需要消费者方面的黑客攻击.

Hacks on consumer side are not needed anymore.

interface Foo { bar(): void }
declare function getFoo(): Foo | undefined;

function assert(value: unknown): asserts value {
    if (value === undefined) {
        throw new Error('value must be defined');
    }
}

function test() {
    const foo = getFoo();
    // foo is Foo | undefined here
    assert(foo);
    // foo narrowed to Foo
    foo.bar();
}

游乐场

另外可以断言提供的参数是必需的类型:

Additionally one can assert that provided parameter is of required type:

declare function assertIsArrayOfStrings(obj: unknown): asserts obj is string[];

function foo(x: unknown) {
    assertIsArrayOfStrings(x);
    return x[0].length;  // x has type string[] here
}

游乐场

这篇关于Typescript 类断言类型保护的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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