打字稿类似断言的类型保护

Zbi*_*ski 6 typescript

这是可能有不限制类型if的函数调用never回报例如undefinedassert在打字稿?

示例代码:

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
}
Run Code Online (Sandbox Code Playgroud)

我希望能够写assert在这样的方式,我可以跳过下面的if (!foo)条款,并有foo限于普通型Foo

这是可能的打字稿?

我试过never为抛出的类型添加重载:

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'})
    }
}
Run Code Online (Sandbox Code Playgroud)

该代码可以编译,但是to的调用assertGuard(foo)无法识别undefined它会返回,never因此不限fooFoo

我发现可能的解决方法,但我认为传统assert清洁方法:

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, ''
Run Code Online (Sandbox Code Playgroud)

Ale*_* L. 27

Typescript 3.7在控制流分析中添加了断言

一个asserts返回类型谓词表示该功能只有当断言持有返回否则抛出一个异常

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

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();
}
Run Code Online (Sandbox Code Playgroud)

操场


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

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

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

操场

  • 是的,我们可能都知道 3.7 的这个伟大功能,我将更新评论以标记该问题已过时。 (2认同)

gaw*_*cks 5

这个https://github.com/Microsoft/TypeScript/issues/8655的打字稿积压中存在一个问题。因此,目前您无法执行此操作。

您可以做的是使用“非空断言运算符”。这迫使打字稿放宽不为null的检查。如果您绝对确定它不会导致空引用,请使用这种情况。

function test() {
     const foo = getFoo();
     assert(foo);
     foo!.bar(); //Dang it typescript! I know better.
}
Run Code Online (Sandbox Code Playgroud)