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

Revisit: Contextually typing classes by their parent class or interface (extends or implements) #52315

Closed
5 tasks done
nmay231 opened this issue Jan 19, 2023 · 4 comments
Closed
5 tasks done

Comments

@nmay231
Copy link

nmay231 commented Jan 19, 2023

Suggestion

πŸ” Search Terms

contextually, infer, type, class, extends, inherit, implements

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

Since the satisfies keyword has been implemented, perhaps the infrastructure is in place to revisit #1373, #3667. The reasons for closing the PR #6118 are no longer valid if implements works more like satisfies than as. In other words, if it checks assignability to a subtype instead of casting to a subtype, just like satisfies does now.

πŸ“ƒ Motivating Example

interface Stack {
  length: number;
  push(val: string): number;
  pop(): string | null;
}

class MyStack implements Stack {
  length = 0;

  // Automatically detects type without annotations!
  push(val) { return ++this.length }

  // MyStack.pop implements `() => string | null` but is correctly typed as `() => string`
  pop() { return "hello world" }

πŸ’» Use Cases

While implements currently does type checking, it does not infer types of methods or attributes and you must manually add types to a class declaration.

interface Stack {
  length: number;
  push(val: string): number;
  pop(): string;
}

class MyStack implements Stack {
  // `val` is implicit any. Sadface :(
  push(val) { /* ... */ }
}
@RyanCavanaugh
Copy link
Member

I believe this is #23911

@nmay231
Copy link
Author

nmay231 commented Jan 20, 2023

Crash dang it. I coulda swore I looked for open issues referencing #6118

@nmay231 nmay231 closed this as completed Jan 20, 2023
@nmay231
Copy link
Author

nmay231 commented Jan 24, 2023

Note, apparently attribute typing is discussed in a separate issue (#10570) than method typing (#23911).

I'm also copying the cautions listed in https://www.typescriptlang.org/docs/handbook/2/classes.html#cautions verbatim so others can potentially find the relevant issues easier:

It’s important to understand that an implements clause is only a check that the class can be treated as the interface type. It doesn’t change the type of the class or its methods at all. A common source of error is to assume that an implements clause will change the class type - it doesn’t!

@ScreamZ
Copy link

ScreamZ commented Mar 15, 2023

I don't understand why this is so complicated, if we switch to interface with the object there is no issue. Can someone explain me ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants