Skip to content

Error 2775 ("explicit type annotation required") for class method type assertions, when instance type seems obvious #47945

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
tomduncalf opened this issue Feb 18, 2022 · 6 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@tomduncalf
Copy link

tomduncalf commented Feb 18, 2022

Bug Report

We have been experimenting with the asserts keyword for type assertions, which seems like a really powerful feature, but we are hitting the issue that class methods which use asserts require an explicit type annotation on the instance (Assertions require every name in the call target to be declared with an explicit type annotation.(2775)).

It seems "obvious" to me in the code sample below that the type of assertingInstance is AssertingInstance, so I don't understand why it requires an explicit type annotation. For our use case (authoring a library), the requirement for users to add an explicit type annotation when consuming the library makes using asserts a non-starter unfortunately.

I have read all the existing issues I can find for this issue, and I do understand why this is required for function calls as described in 45385 and 34596, but I'm not clear on why this should apply for the case of an instance of a class. Perhaps I'm missing some way in which the type is not as "obvious" as it seems?

It would be really nice if we could use this feature on classes without explicit annotations, but if there are technical reasons why this isn't possible, I'd love to understand them and to know if this might one day be possible. I'd also be interested to know if there are any workarounds which do not require consumers to add an explicit type annotation.

🔎 Search Terms

type assertion, asserts, explicit type annotation, 2775, class, instance, method

🕗 Version & Regression Information

v4.5.4

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about class method assertions

⏯ Playground Link

Playground link with relevant code

💻 Code

type X = {
  x: number;
};

type Y = {
  y: number;
} & X;

class AssertingClass {
  assertIsY(obj: X | Y): asserts obj is Y {
  }
}

const x: X = { x: 1 };

const assertingInstance = new AssertingClass();
assertingInstance.assertIsY(x); // Error 2775: Assertions require every name in the call target to be declared with an explicit type annotation.(2775)
x.y; // Error, because x is not a Y

const explicitAssertingInstance: AssertingClass = new AssertingClass();
explicitAssertingInstance.assertIsY(x);
x.y; // OK, because x is now a Y

🙁 Actual behavior

Error 2775: Assertions require every name in the call target to be declared with an explicit type annotation.(2775)

🙂 Expected behavior

Typescript to infer that the type of assertingInstance is AssertingClass without the type annotation, and so allow the asserts keyword ot be used without an explicit annotation.

@nmain
Copy link

nmain commented Feb 18, 2022

Even obvious inferences require inference to happen before the compiler can know about them. Inference is done in a single pass and requires knowledge of where all the assert calls are before it runs.

@RyanCavanaugh
Copy link
Member

It seems "obvious" to me in the code sample below that the type of assertingInstance is AssertingInstance, so I don't understand why it requires an explicit type annotation

It might seem like new AssertingClass() always has the type AssertingClass, but this is not the case. Until the constructor call is actually processed, we don't know that something like this hasn't happened:

declare const AssertingClass: {
  new(): SomeType;
  new(arg: number): SomeOtherType;
}

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Feb 18, 2022
@tomduncalf
Copy link
Author

Ah, interesting point @RyanCavanaugh, I had not looked at it like that. Thanks for the reply!

Do you think there might be a path to supporting our use case (exporting a class which uses asserts, without requiring end-users to add type annotations) in future?

@RyanCavanaugh
Copy link
Member

It's always possible we'll get smarter in the future, but I don't see a straightforward way to fixing that particular scenario right now without incurring the sort of performance penalty (10%+ on all programs IIRC) that has kept us from doing this analysis so far.

@tomduncalf
Copy link
Author

That's good to know. Thanks for the help and for all the great work you and your team are doing!

@StepanMynarik
Copy link

Perhaps this limitation could be re-investigated after migrating the compiler to Go?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

4 participants