-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Prevent class or its methods from overriding. With keyword like final
or sealed
.
#50532
Comments
Yes, more or less. And now we have a well described issues which takes care about class and its methods and fields with examples and possible solutions. Btw. I only knew the closed issue #8306. Which was closed for incomprehensible reasons. See closing post. |
it a 8 year feature request :) |
I expected this to exist only to find out that it didn't. Bit of a shame maintainers don't see value in this (my assumption based on the fact that it doesn't exist and similar issues have been closed without resolving). |
Really handly feature. I think better to work on this feature than playing with |
I suggest removing the duplicate flag and instead mark #8306 as a duplicate of this issue here. 8306 was initially about final classes and was closed as "won't fix" for the wrong reasons (misunderstanding about runtime performance optimizations). This new issue here is about final methods AND classes, is described in great detail and makes clear that it is NOT about runtime optimizations. So please lets discuss about this very useful language improvement and do not blindly close this issue in favor of 8306. Typescript already has The same goes for methods. We can define methods which MUST be implemented ( |
This should have been on the feature list from day 1, or at least when the explicit |
@infacto I think the
|
Final (or sealed) methods are a critical tool in writing utility classes that can safely and reliably extended. So I totally concur with this new attempt to get them added to Typescript. |
ECS pattern is a great example of usage of final for classes components. |
This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
This is a sad reaction from the TypeScript team. I think we just want an understandable statement. It's okay if you say you don't want to do this for internal reasons or concerns. But instead we get confusing or dubious answers like this. It's just rude and not the truth. We just want a statement. Not answering is ignorant. You're probably just annoyed. I understand that when I look in the issue tab. But anything is more helpful than that. It deserves a few respectful and explanatory words. Nobody is forcing you to implement everything the community suggests. I think you are professionals and closing issues like this or the others must be a valid reason. But for what reason? We just want to understand. |
The way this feature is handled disheartens me for almost a decade, and all this without a viable reason is at this point imo like shouting "we don't care, and neither should you". |
This is very disappointing, especially when the official TypeScript documentation even gives this exact scenario as an example of use of class decorators. Only issue is, that the decorator solution will cause an error at runtime instead of dealing with it at design time. #shiftright π€¦ββοΈ |
Classic Microsoft, right? |
[updated] Does this help? (At the method or attribute level) declare const _: unique symbol;
type Forbidden = { [_]: typeof _; }
type NoOverride<T=void> = T & Forbidden;
function makeNoOverride<T>(value: T): NoOverride<T> {
return value as any;
}
class A {
readonly baz: NoOverride<string> = makeNoOverride('');
foo(): NoOverride<{ a: string }> {
return makeNoOverride({ a: '' });
}
// if this function return nothing, use `NoOverride` only
bar(): NoOverride {
console.log(0);
}
}
class B extends A {
// @ts-expect-error - Type 'string' is not assignable to type 'NoOverride'.
baz = '';
// @ts-expect-error - Property '[_]' is missing in type '{ a: string; }' but required in type 'NoOverride'.
foo() {
return { a: '' };
}
// @ts-expect-error - Type 'void' is not assignable to type 'NoOverride'.
bar() {
}
} cc @vddrift |
Works for me! Thanks @Max10240 ! I like to wrap it like this:
|
@andrewbranch |
Interesting approach. You could simplify it further by leaving out some more typescript: Personally I like to separate concerns. So I prefer this, which is clearly Typescript
Over this, which is javascript used to fix a Typescript issue
Perhaps the following is the cleanest way to set a value baz and then declare it as NoOverride
|
Yes, for the most part, like you, I prefer to let TS do its own type inference, like: // prefer:
let s = '...';
const baz = makeNoOverride('');
// than:
let s: string = '...';
const baz: NoOverride<string> = makeNoOverride(''); But for function return values, I prefer to declare the return type explicitly (so that the code reader can see it from the start). So the final version in my mind looks something like this: declare const _: unique symbol;
type Forbidden = { [_]: typeof _; }
type NoOverride<T=void> = T & Forbidden;
function makeNoOverride<T>(value: T): NoOverride<T> {
return value as any;
}
class A {
readonly baz = makeNoOverride('');
foo(): NoOverride<{ a: string }> {
return makeNoOverride({ a: '' });
}
// if this function return nothing, use `NoOverride` only
bar(): NoOverride {
console.log(0);
}
}
class B extends A {
// @ts-expect-error - Type 'string' is not assignable to type 'NoOverride'.
baz = '';
// @ts-expect-error - Property '[_]' is missing in type '{ a: string; }' but required in type 'NoOverride'.
foo() {
return { a: '' };
}
// @ts-expect-error - Type 'void' is not assignable to type 'NoOverride'.
bar() {
}
} ps: Friendly communication as a personal code style only :) |
We need a decorator for sealing functions and properties to either flag them to now allow override in subclasses or change the value after sealing. Is there a property for that which can be toggled by a typescript decorator? I know we can now seal a class. |
Suggestion
π Search Terms
β Viability Checklist
β Suggestion
There are situations when you want to avoid other classes overriding the entire class or just some methods or fields.
For these cases there are keywords in other languages like Java or C#. Called
final
orsealed
/virtual
, etc.TypeScript could take inspiration from these keywords or find its own way. Which we want to find in this issue.
This way or keyword is for TypeScript only. There is no need for optimization on runtime or effect on generated code. It's a part of type definition and acts similar like keywords
readonly
,public
,abstract
,protected
, etc. It's only about hints during development.π Motivating Example
Let me show an example what brought me here:
Or using the C# variant using keywords like
sealed
. More examples are welcome.π» Use Cases
In some cases you want to control which classes or methods can be overridden by derived classes. For example, you have a class with configuration methods and you don't want active methods to be able to be overridden. It's also relevant for defintion files
d.ts
in APIs.We could also check out the uses cases from other language why these keywords exists. Even if Java and/or C# uses the final class to optimize the class at runtime. TypeScript is at the type level and only acts during development to prevent overwriting like similar related features. ...
For more information, see the links below:
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed
https://docs.oracle.com/javase/tutorial/java/IandI/final.html
Background: I know Java and C#. But I'm not a Java or C# developer. My information is based on research on web.
The text was updated successfully, but these errors were encountered: