Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Destructuring assertions gives unexpected results #37818

Closed
kitsonk opened this issue Apr 6, 2020 · 4 comments
Closed

Destructuring assertions gives unexpected results #37818

kitsonk opened this issue Apr 6, 2020 · 4 comments
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@kitsonk
Copy link
Contributor

kitsonk commented Apr 6, 2020

TypeScript Version: 3.8.3

Search Terms:

TS2775, assert destructure

Code

const Deno = {
    assert(actual: unknown): asserts actual {
        if (actual == null) {
            throw new TypeError("Assertion failed!");
        }
    }
}

const { assert } = Deno;

assert("foo"); // fails

const { assert: assert2 }: { assert: (actual: unknown) => asserts actual } = Deno;

assert2("foo"); // fails

const assert3: (actual: unknown) => asserts actual = Deno.assert;

assert3("foo");

Expected behavior:

assert and assert2 do not produce errors, like assert3.

Actual behavior:

assert and assert2 generate TypeScript error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.

I am not sure why they can't be destructured and the type applied, and can't figure a logical reason why this would be prohibited. Is it because the symbols could get mixed-up/confused when destructuring? Feels like that could be statically determined though.

Playground Link: link

Related Issues:

@nmain
Copy link

nmain commented Apr 7, 2020

The error message is correct. A limitation of the typescript compiler is that the signatures of assert functions must be known at their call sites before type inference runs. Because of #7576, you won't be able to do this with destructuring.

@sandersn sandersn added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Apr 8, 2020
@kitsonk
Copy link
Contributor Author

kitsonk commented Apr 29, 2020

I get that destructuring with type annotations could fix it, but I don't understand why the assertion type can't be destructurally inferred, there is no craziness there. I can understand that this currently is unaddressed, but is a design limitation the end of the road for this? Seems likely a really silly and surprising one.

@nmain
Copy link

nmain commented Apr 29, 2020

I did not say it could not be inferred. It can be and is trivially inferred. But all assertion signatures must be known before any inferences run.

The limitation runs deep and I probably won't do a good job explaining it, but:

a;
f(a);
a;

Here, if f is an assertion function, then a could have two different types before and after the call. So it needs an extra node on the control flow graph, and any type inferences that depend on a will be affected by this.

If it is not known whether f is an assertion function until we infer the type of f, then the control flow graph needs to be rewritten after the fact and a new inference pass needs to run. Adding extra passes like this is slow and messy. Defensively assuming every function call might be an assertion would work, but is also very slow.

Hopefully that helps a bit. #32695 was a difficult problem and the limitation is not silly.

@kitsonk
Copy link
Contributor Author

kitsonk commented Apr 29, 2020

I did say it seems like a really silly one. My assumption, which appears to be incorrect, is that the TypeScript compiler doesn't trivially infer types at the destructuring point, but at the call point. I am super thankful for #32695 and I think Anders knows that.

If it is not a simple design limitation to address, at least the error message is a bit unapproachable. @DanielRosenwasser you are always on the hunt for bad UX message. This one falls into it in my opinion. Maybe:

TS2775: Assertion return types require the function or method to have an explicit type annotation, and cannot be inferred. Try declaring the type explicitly on this function or method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

4 participants