π Search Terms
- protected alternative
- internal
Related issues:
β
Viability Checklist
β Suggestion
Currently, protected causes several issues:
- you can't use duck typing when a class have a
protected property. You can't implement it, you are required to extend it.
protected (and private) properties often disappear when manipulating types.
I'd like an internal modifier that would behave similarly to readonly.
It would declare the property is part of the public interface, but you can't access it outside of its methods (a.k.a. functions where the type of this is the type of the instance).
π Motivating Example
Such feature could be used for several usages.
Having friends
Currently, TS has no friend, even though this seems to be a frequently requested feature:
An internal modifier would be a cleaner way to have friends:
- you declare a function/class with some internal properties.
- you can safely cast such object by removing the
internal modifier with some type manipulations (e.g. with -internal).
You can then select exactly which properties are accessibles from friends (which helps respecting encapsulation).
Implementing classes with internal properties
Sometimes we want to implement a class instead of extending it. However, this is not possible when using protected properties:
Defining interfaces with internal properties
We could also define interfaces with internal properties, e.g. hooks that could be overridden when extending a class implementing the interface, without even requiring to know the class true concrete type.
Manipulating internal properties
This would also enable more complex type manipulations, e.g.:
π» Use Cases
Currently, there are several workarounds.
Cast
const internal = target as FooInternals;
Can be dangerous. A "type map" can be used to make the cast slightly more secure, but this is still unsafe.
Public properties
Making the properties public solves most of the issue, however, this makes properties publicly accessible, loosing some protections.
Symbols
We can hide the internal type behind a symbol.
class Foo {
[SYMBOL] = this as InternalFoo;
// or
[SYMBOL] = { ... }
}
However, this is not ideal when manipulating classes in mixins (attributes aren't accessible from the prototype, and we can't really manipulate the constructor).
Hooks in the constructor
In some cases, you can give hooks in the base class constructor instead of overriding protected methods.
class Foo {
[HOOKS]: XX; // not in the FooClass interface.
constructor(hooks) {
this[HOOKS] = hooks;
}
}
But same as previously, this is not ideal when manipulating classes in mixins.
Static properties
Another way is to declare static instance methods that can be redefined:
class X {
static onChange = () => {};
foo() {
this.constructor.onChange.call(this); // not type safe.
}
}
However this is not truly type safe:
Alternative suggestion :
This issue could also be solved by specifying a public and an internal type for the same property:
The usage could then be something like foo: $PUB_TYPE @internally=$INTERNAL_TYPE, e.g.:
foo: never @internally=number.
foo: readonly number @internally=number.
foo: X @internally=XInternals.
However this would require bigger changes to TS.
π Search Terms
Related issues:
β Viability Checklist
β Suggestion
Currently,
protectedcauses several issues:protectedproperty. You can't implement it, you are required to extend it.protected(andprivate) properties often disappear when manipulating types.I'd like an
internalmodifier that would behave similarly toreadonly.It would declare the property is part of the public interface, but you can't access it outside of its methods (a.k.a. functions where the type of
thisis the type of the instance).π Motivating Example
Such feature could be used for several usages.
Having friends
Currently, TS has no friend, even though this seems to be a frequently requested feature:
friendorInternalsVisibleToΒ #35554An
internalmodifier would be a cleaner way to have friends:internalmodifier with some type manipulations (e.g. with-internal).You can then select exactly which properties are accessibles from friends (which helps respecting encapsulation).
Implementing classes with internal properties
Sometimes we want to implement a class instead of extending it. However, this is not possible when using
protectedproperties:implementson abstract classes with protected members (usefull for generic mixins)Β #61161Defining interfaces with internal properties
We could also define interfaces with internal properties, e.g. hooks that could be overridden when extending a class implementing the interface, without even requiring to know the class true concrete type.
Manipulating internal properties
This would also enable more complex type manipulations, e.g.:
π» Use Cases
Currently, there are several workarounds.
Cast
Can be dangerous. A "type map" can be used to make the cast slightly more secure, but this is still unsafe.
Public properties
Making the properties public solves most of the issue, however, this makes properties publicly accessible, loosing some protections.
Symbols
We can hide the internal type behind a symbol.
However, this is not ideal when manipulating classes in mixins (attributes aren't accessible from the prototype, and we can't really manipulate the constructor).
Hooks in the constructor
In some cases, you can give hooks in the base class constructor instead of overriding protected methods.
But same as previously, this is not ideal when manipulating classes in mixins.
Static properties
Another way is to declare static instance methods that can be redefined:
However this is not truly type safe:
Alternative suggestion :
This issue could also be solved by specifying a public and an internal type for the same property:
The usage could then be something like
foo: $PUB_TYPE @internally=$INTERNAL_TYPE, e.g.:foo: never @internally=number.foo: readonly number @internally=number.foo: X @internally=XInternals.However this would require bigger changes to TS.