Repository: TypeScript
Issue: Allow 'declare' on methods and constructor
Labels: Suggestion,In Discussion

# Suggestion

Allow `declare` on methods and constructor of a (non-`declare`d) class.

## 🔍 Search Terms

"declare modifier cannot appear on class elements of this kind"
"TS1031"
"1031"

## ✅ 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](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).

## ⭐ Suggestion

It is currently not possible to use `declare` on methods (including the constructor) of a (non-`declared`) class. TypeScript responds with the error

````
'declare' modifier cannot appear on class elements of this kind.(1031)
````

However, there are use cases where I would like to refine the type of a method or the constructor in a subclass without changing the implementation.

So, like for fields, I suggest to allow `declare` on methods and the constructor, too.

## 📃 Motivating Example

<!--
  If you were announcing this feature in a blog post, what's a short explanation that shows
  a developer why this feature improves the language?
-->

In a subclass, overriding methods are allowed to change parameter types to compatible types. Usually, a different method signature means a different implementation, too, but there are cases where inheriting the implementation would be fine, and I just want to declare the changed method signature. This is often the case if the inherited implementation delegates to another method, which is overridden with a changed method signature in the subclass.

Here is a [TypeScript playground link to a working example](https://www.typescriptlang.org/play?#code/FAYwNghgzlAECCsDexZthAXLAdgVwFsAjAUwCdYBeWARgG5gBfYUSGWAIVhIA8AXEjgAmcRCnSwi2KHzIBLHAHMqsAEQdVDZq2hwAyngAO5ZKnQgA9jhlk8IPhbIAKAG4QweEtngBKUxIk+AAs5KAA6BTk+V3dPHwYJZglDMgsBexIhWEjotw8vBD9xAMtrCzASMLALRSdVCFUAGlg8zzCIeLM0Zm1wXVgDIm5+QREBoxNitAB6aYABPigAWjlFHEcCgHcggE9YEAgcAHI+WABJWCESPrISDFgCDdgoYxA5ADM5EFhDCDIIAgkAQUPg7YywTZRIIWPCnOQEQwVQE4PgKZRRAD8XUu10gt32VhsdgczlaBQ4nWSqXSAiyFhc5HkV2yOCiMXy2Ap-gCaCgEzIEVZuViJEpPIJZQqVRqdSITRaIrCRDF3SYLBwJE24yITiQGGwACZmlI1BwAKJm1SwRidIA).

The example defines a class `Super` whose constructor takes some configuration object of type `A`. The constructor of its subclass `Sub` takes a parameter of `B`, which is a sub-type of `A`.

The constructor of `Super` delegates to method `init`, which also has parameter type `A`. Thus, overriding `init` in `Sub` to support parameter type `B` _implies_ that `Sub`'s constructor now also supports arguments of type `B`. 

Now, it would be nice if we could just _declare_ the new signature of `Sub`'s constructor, instead of implementing it with boiler-plate code that simply hands through the arguments.

While TypeScript allows to use the `declare` keyword on fields, it forbids to use it on methods and constructors. The example uses `@ts-ignore` to show that if I override this restriction, I get exactly the result that I want: `new Sub(...)` now expects a parameter of type `B`. The implementation of `Sub`'s constructor is inherited from `Super` and delegates to the (overridden) `init` method.

## 💻 Use Cases

Workaround 1 is shown in the example: Use `@ts-ignore` or `@ts-expect-error` to ignore this error (TS1031). Ugly, but works.

Workaround 2: Of course, you can implement the subclass constructor by calling `super` and handing through all parameters, but this results in boiler-plate code and even adds run-time overhead.

Similar use cases as in the motivating example would be to specify a method (instead of the constructor) whose signature is changed in the subclass without changing its implementation. For that use case, there is another workaround, so I'm missing the feature for constructors more desperately. For methods, you can take advantage of declaration merging and specify the new signature in an interface with the same name as the subclass. But even that results in more code than simply using the `declare` keyword. Both this use case and the workaround are shown in [this second TypeScript playground example](https://www.typescriptlang.org/play?#code/FASwdgLgpgTgZgQwMZQAQEFUG9ir6hALlTAFcBbAI1gG5gBfYUSWRFVAIVSgA9owAJgGcM2XPkrEhEGOADmdRsCQAbBEJEBlUgAdYY-KiQwoCaAAoAbghWkoxdAEpClgPYgBBw-ggALEEIAdOAgEFY2do50hoyGOjCu0EjQniFh1rb2GI5ehkiuYEKuKlCBKq5y5gBECFUANKgZdoEIUeJ4jEqq6lqklNx8UIK9ejC5qPGJUMlQnq6WsLICaGnhmcQcOTje+EK6sMFgoWuR0TtGBUUlZRXVlPWNEaWUbTHtqAD0HySJBCrlAHdZqhzAAVTQARgADABmCHOd5fVDLbomIwmMxQE5ZTbENweOgMJhIgGuGAAawQCVIgmIpCEaBRahgZhABVQ5FgcnkqAgrmR02ZaD8aDAUABqCEIDkYDMpBMhGY0HgyDQ2n623wxlMFiaOOcjXcAkUTDFEvV5kcgW1mPMWAIxAATA1JKgqhwAKIeqqoehtIA).