Repository navigation
Allow 'declare' on methods and constructorΒ #48290
Description
Suggestion
Allow declare on methods and constructor of a (non-declared) class.
π Search Terms
"declare modifier cannot appear on class elements of this kind"
"TS1031"
"1031"
β 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
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
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.
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.
Activity
fatcerberus commentedon Mar 16, 2022
This is exactly what
@ts-expect-errordoes, by design: if thereβs no error on the guarded line, the ts-expect-error comment itself produces an error. This is specifically so you know to delete the comment when/if a known type system bug/limitation gets fixed. If that were considered a breaking change, no such improvements could ever be made to the type system ever again, defeating the purpose of the directive. πfwienber commentedon Mar 17, 2022
Thanks! That's exactly what I was hoping you'd answer, and I just added the remark to be on the safe side. Since you say it is redundant, I removed the remark from the description.
jcalz commentedon Jun 26, 2023
linking to #38008
xiaoxiyao commentedon Nov 19, 2024
Any plans about this?