Skip to content

Partial application of functions loses type assertion information #46702

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

Closed
samuela opened this issue Nov 5, 2021 · 4 comments
Closed

Partial application of functions loses type assertion information #46702

samuela opened this issue Nov 5, 2021 · 4 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@samuela
Copy link

samuela commented Nov 5, 2021

Bug Report

🔎 Search Terms

type assertion, assert v is T, asserts condition, partial application, type inference, case splitting

🕗 Version & Regression Information

  • This is the behavior in every version I tried, including 4.4.4 and 4.5.0-beta

⏯ Playground Link

Playground link with relevant code

💻 Code

// See https://github.com/Microsoft/TypeScript/issues/7556.
type ErrorT = { new (message: string): Error };
type Either = { tag: "Left"; a: string } | { tag: "Right"; b: number };

// --- Explicit version (assertion type information is propagated):
function assertExplicit(condition: boolean): asserts condition {
  if (!condition) {
    throw new Error("oops");
  }
}
function testWorks(x: Either) {
  assertExplicit(x.tag === "Right");
  console.log(x.b);
}

// --- Partial application version (assertion type information is lost):
function _assert(errorType: ErrorT, condition: boolean): asserts condition {
  if (!condition) {
    throw new errorType("oops");
  }
}
const assert = (condition: boolean) => _assert(Error, condition);
function testFails(x: Either) {
  assert(x.tag === "Left");
  console.log(x.a); // fails with "Property 'a' does not exist on type 'Either'."
}

export {};

🙁 Actual behavior

Type assertion information is lost outside of immediate call-sites. For example, if f(x): asserts <condition> then TS will only respect the assertion of the condition in the direct scope of where f is called and nowhere else, eg if g call f, there is no propagation of the information that asserts <condition> should hold in g.

🙂 Expected behavior

Assertion types to be propagated everywhere they apply.

@MartinJohns
Copy link
Contributor

Working as intended. assert is not an asserting function. See #32695.

@andrewbranch andrewbranch added the Working as Intended The behavior described is the intended behavior; this is not a bug label Nov 5, 2021
@samuela
Copy link
Author

samuela commented Nov 5, 2021

But why is assert not an asserting function? Simple control-flow analysis should reveal that it ought to have the same asserting properties as _assert since there's no try/catch in assert.

@devanshj
Copy link

devanshj commented Nov 8, 2021

As pointed out in #32695 these are the conditions for participation in CFA:

A function call is analyzed as an assertion call or never-returning call when

  • the call occurs as a top-level expression statement, and
  • the call specifies a single identifier or a dotted sequence of identifiers for the function name, and
  • each identifier in the function name references an entity with an explicit type, and
  • the function name resolves to a function type with an asserts return type or an explicit never return type annotation

assert doesn't fulfil the third condition, it's not explicitly typed. There is a feature request to lift this condition: #45385

@typescript-bot
Copy link
Collaborator

This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

5 participants