Repository: TypeScript
Issue: TS Proposal : "Interface incorrectly extends interface" - sub-interface method overload OR override ?
Labels: Suggestion,Needs Proposal

**TypeScript Version :**  2.6.2

## The problem

**Initial scenario**

I encountered the issue yesterday days as I was trying to add some features to one of my interface inheritance chain. The context of this example is just imagined : It is longer than needed to demonstrate the issue, but I wanted a full example to clearly show it needs to be addressed.

So, let's imagine a testing app that should instrument devices : the following is a potential model of the situation :

```ts
interface Stream
{
}
interface InputStream
{
}
interface OutputStream
{
}
// interface inheraitance is a great feature
interface IOStream extends InputStream, OutputStream
{
}
```

```ts
interface InterfaceLike
{
}
interface DeviceInterfaceLike extends InterfaceLike
{
    init();
}
interface InputDeviceInterfaceLike extends DeviceInterfaceLike
{
    input(); // this should word just like the `touch` command
             //     like if there's and error with the device, it will trigger exception
    input(stream: InputStream);
}
```

```ts
interface ScreenDeviceInterfaceLike extends InputDeviceInterfaceLike
{
    input(stream: InputStream, coordinates: {x: number, y: number});
}
interface TouchScreenDeviceInterfaceLike extends InputDeviceInterfaceLike
{
    input(stream: IOStream, coordinates: {x: number, y: number});
}
```

**Expected behavior :**

It should just overload that method in the sub-interfaces.

**Actual behavior :**

```
error TS2430: Interface 'ScreenDeviceInterfaceLike' incorrectly extends interface 'InputDeviceInterfaceLike'.
  Types of property 'input' are incompatible.
    Type '(stream: InputStream, coordinates: { x: number; y: number; }) => any' is not assignable to type '{ (): any; (stream: InputStream): any; }'.
core.ts(73,11): error TS2430: Interface 'TouchScreenDeviceInterfaceLike' incorrectly extends interface 'InputDeviceInterfaceLike'.
  Types of property 'input' are incompatible.
    Type '(stream: IOStream, coordinates: { x: number; y: number; }) => any' is not assignable to type '{ (): any; (stream: InputStream): any; }'.
18:38:26 - Compilation complete. Watching for file changes.
```

It requires me to fully copy paste all method signatures in each interface.

```ts
interface ScreenDeviceInterfaceLike extends InputDeviceInterfaceLike
{
    input(); // this should word just like the `touch` command
             //     like if there's and error with the device, it will trigger exception
    input(stream: InputStream);
    input(stream: InputStream, coordinates: {x: number, y: number});
}
interface TouchScreenDeviceInterfaceLike extends InputDeviceInterfaceLike
{
    input(); // this should word just like the `touch` command
             //     like if there's and error with the device, it will trigger exception
    input(stream: InputStream);
    input(stream: IOStream, coordinates: {x: number, y: number});
} 
```

When you're can have up to (why not) 15 overloads distributed through inheritance chain... It becomes, (yes, you said it) bulky.

-----

Now it is, that the compiler cannot yet figure out when to `override` the method signatures inherited from parents and when to `overload` them.

## The Proposal

My first thought was to introduce a new keyword just like `@ts-nocheck` and like.

### `@override`

```ts
interface InputDeviceInterfaceLike extends DeviceInterfaceLike
{
    @override // to override all definitions from parents
    init(istream: InputStream);
}
```
OR
```ts
interface InputDeviceInterfaceLike extends DeviceInterfaceLike
{
    @override
    {
        init(); // to override only this (these) definitions : forget all previous definition but this (these)
    }
    init(istream: InputStream);
}
```

Then, the `TouchScreenDeviceInterfaceLike` interface would become :

```ts
interface TouchScreenDeviceInterfaceLike extends InputDeviceInterfaceLike
{
    @override   // it is now clear that the only way to instrument a touchscreen is to provide a `IOStream` and coordinates (`{x: number, y: number}`)
    input(stream: IOStream, coordinates: {x: number, y: number});
}
```

### Furthermore, `@overload`

While the previous **`@override` is useful when the default behavior is oveloading**, we can still define the default behavior to **suppress all parent definition WHEN A METHOD IS REDEFINED in subinterface, except when `@overload` is used**. i.e

```ts
interface InputDeviceInterfaceLike extends DeviceInterfaceLike
{
    // to override all definitions from parents
    init(istream: InputStream);
}
```

OR

```ts
interface InputDeviceInterfaceLike extends DeviceInterfaceLike
{
    @overload // to overload signatures from parents
    init(istream: InputStream);
}
```

And `TouchScreenDeviceInterfaceLike` interface can become :

```ts
interface TouchScreenDeviceInterfaceLike extends InputDeviceInterfaceLike
{
    @overload                           // to overload signatures from parents
    {
        init(istream: InputStream);     //      except this signature... So that it remains only the empty parameter and the below
    }
    input(stream: IOStream, coordinates: {x: number, y: number});
}
```

----

By thinking rigorously, I think the first step would be allow inheriting type to overload methods by default.

**= = = = = = UPDATE = = = = = =**
I now think it worth to add that by no mean, all through an interface inheritance chain should a method be completely wiped off (deleted, removed)... Not even by `@Override`! As this may (will) break the core concept of OOP inheritance.

The mechanism is to ensure that only some methods mood (signatures) are handled (accepted) at a given inheritance node.

In other words, if `@Override` suppresses all signatures, at least one method signature MUST be required.