Skip to content

Add override / noImplicitOverride support for interfaces #45136

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

Open
5 tasks done
dominic-simplan opened this issue Jul 21, 2021 · 12 comments
Open
5 tasks done

Add override / noImplicitOverride support for interfaces #45136

dominic-simplan opened this issue Jul 21, 2021 · 12 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@dominic-simplan
Copy link

Suggestion

πŸ” Search Terms

noImplicitOverride interface override

βœ… 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

πŸ“ƒ Motivating Example

The new override keyword in TS4.3 works for classes but not for interfaces.
Would be great to have it also available for interfaces. As interfaces are technically not overridden, alternatively a new keyword like implement could be introduced (Java, for example, uses override for classes and interfaces though)

πŸ’» Use Cases

What is the advantage of override / noImplicitOverride for interfaces? Consider this case:

interface ISomething {
  doSomething?: () => void;
}

class Something implements ISomething {
  doSomething: () => {console.log("Something")}
}

If you rename doSomething() in the interface to doSomethingElse(), this would not throw an TS error, since it is optional and therefore doesn't have to be implemented. The implementing class would still have a doSomething() method which never gets executed.

If I would be forced to do something like this, TS could throw an error if I rename doSomething in the interface:

class Something implements ISomething {
  override doSomething: () => {console.log("Something")}
}

Currently I am using a custom TSLint rule via eslint but TSLint is already deprecated and also the rule stopped working with TS 4.3.
An according ESLint is not planned for this.
Anyhow, I think this check could be done directly in TS.

@Kingwl
Copy link
Contributor

Kingwl commented Jul 21, 2021

/cc: @DanielRosenwasser @sandersn

@MartinJohns
Copy link
Contributor

Although this is intentional:

#44439 (comment)

It's intentional that override doesn't apply to implements clauses, since you're not overriding anything.

@andrewbranch andrewbranch added Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript labels Jul 21, 2021
@VsevolodGolovanov
Copy link

I want to be able to override even just for documentation:

interface A {
	/**
	 * Bla-bla.
	 */
	doStuff: () => void;
}

interface B extends A {
	/**
	 * Bla-bla, but in the context of B: additional concerns and ramifications etc.
	 */
	override doStuff: () => void;
}

@HaraldKi
Copy link

This would also help to notice possibly unused exported methods when an interface is removed from the implements clause and the method is no longer necessary.

@KutnerUri
Copy link

yup this makes sense. could reuse the implements keyword.

@Trass3r
Copy link

Trass3r commented Aug 8, 2022

It's intentional that override doesn't apply to implements clauses, since you're not overriding anything.

Imo it's totally fine to re-use override for this.
It may not be technically correct but at least it's consistent, easily understandable and doesn't require any code changes when you replace an interface with a base class for example.

@KutnerUri
Copy link

KutnerUri commented Aug 22, 2022

on second thought, I realize why this unpopular:
The override keyword is mainly a backup for when "something bad happens" and doesn't provide any direct value.

Perhaps we can move this to JSdocs? There is already some cross-compatibility between JSdocs and TS, maybe we can use the @implements syntax?

  • clears ambiguity with more-than-one base interface
  • causes less disturbance when reading the code
  • can still be enforced, and auto completed
class Cat implements Animal {
  /** @implements Animal */
  clone() { return new Cat(this.name); }
}

@cristan
Copy link

cristan commented Nov 7, 2023

Note that this is exactly how Kotlin already does this: whenever you implement a method, you'd add the override keyword for every method you're implementing from the interface. The only difference is that this is actually required in Kotlin, but we can solve that by either extending the noImplicitOverride flag to also apply to interfaces or add a new flag.

@Bessonov
Copy link

Folks, don't forget to vote for this request! 🀝

Just wanted to emphasize the original poster's point that Java has had it since 2006, long before Kotlin was even a dream :D However, I love the idea of making it mandatory.

In addition, I would love more type inference. For example, this doesn't work:

interface ITest {
    test(arg: string): number
}

class Test implements ITest {
    test(arg) { // Parameter 'arg' implicitly has an 'any' type.(7006)
        return arg.length
    }
}

While it seems to be the right (and unfortunate) thing for TypeScript, something like the override keyword could help there.

@h-joo
Copy link
Contributor

h-joo commented Jan 30, 2024

I feel it would be a great built-in feature to improve documentation and detect correctness. (More weight on the documentation side in complex classes)

@menof36go
Copy link

Without this feature, it is difficult to use type guards effectively.

interface ITest {
  mySpecialProperty: true;
  doSth(): number;
}

function isITest(obj: any): obj is ITest {
  return obj?.mySpecialProperty === true;
}

class Foo implements ITest {
  mySpecialProperty = true as const;
  doSth() {
    return 42;
  }
}

const foo = new Foo();
if (isITest(foo)) {
  console.log(foo.doSth());
}

Eventually, ITest is removed from Foo, but the property used for the type guard is overlooked.

class Foo {
  mySpecialProperty = true as const;
}

const foo = new Foo();
if (isITest(foo)) {
  console.log(foo.doSth()); //Error
}

If we had override, this could not happen.
If we do not get runtime information about interfaces, at least let us make sure that stuff works at design time

@ehe0
Copy link

ehe0 commented Mar 11, 2025

I don't see any downsides to this and it makes and helps keeping the code more clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests