TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Add override / noImplicitOverride support for interfaces

Open dominic-simplan opened this issue 4 years ago • 12 comments

Suggestion

🔍 Search Terms

noImplicitOverride interface override

✅ Viability Checklist

My suggestion meets these guidelines:

  • [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • [x] This wouldn't change the runtime behavior of existing JavaScript code
  • [x] This could be implemented without emitting different JS based on the types of the expressions
  • [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • [x] 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.

dominic-simplan avatar Jul 21 '21 09:07 dominic-simplan

/cc: @DanielRosenwasser @sandersn

Kingwl avatar Jul 21 '21 09:07 Kingwl

Although this is intentional:

https://github.com/microsoft/TypeScript/issues/44439#issuecomment-856310109

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

MartinJohns avatar Jul 21 '21 09:07 MartinJohns

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;
}

VsevolodGolovanov avatar Aug 06 '21 13:08 VsevolodGolovanov

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.

HaraldKi avatar Dec 29 '21 12:12 HaraldKi

yup this makes sense. could reuse the implements keyword.

KutnerUri avatar Jul 03 '22 13:07 KutnerUri

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.

Trass3r avatar Aug 08 '22 12:08 Trass3r

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); }
}

KutnerUri avatar Aug 22 '22 16:08 KutnerUri

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.

cristan avatar Nov 07 '23 12:11 cristan

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

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.

Bessonov avatar Jan 21 '24 17:01 Bessonov

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)

h-joo avatar Jan 30 '24 20:01 h-joo

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

menof36go avatar Jan 23 '25 13:01 menof36go

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

ehe0 avatar Mar 11 '25 09:03 ehe0