f# Readonly on Exports from Namespaces (#16720)
namespace N {
export class C { }
}
N.C = class {};
- Namespaces have had this feature for a while now
- Breaking changes for something that's functioned that way this long seems strange.
- Declined
Readonly & Variance
-
One thing that comes up quite a bit is strict variance.
-
If we enabled stricter variance, that would imply that Array becomes invariant.
- To get a covariant array, you need a
ReadonlyArray.
- This means everything gets two declarations -
T and ReadonlyT
-
Strict variance is easy to enable, but would be hard to make easy to use.
-
This leads us to start thinking about how to quickly make a readonly version of a type.
-
We've had an experimental type operator called readonly
- Much like
keyof T, you just write readonly T.
-
Like the Readonly mapped type, it makes all properties readonly as well.
- However, the
Readonly<T> mapped type doesn't eliminate mutating methods at all.
-
This means we needed to add a way to indicate that a method doesn't mutate its object.
- Created the
this: readonly syntax.
-
Example:
class Foo {
name: string;
getName(this: readonly): string;
setName(value: string): void;
}
// This:
type ReadonlyFoo = readonly Foo;
// ... is equivalent to this:
type ReadonlyFoo = {
readonly name: string;
readonly getName(this: readonly): string;
}
-
What about deep readonly?
- In other words, does
readonly Foo[] give you a readonly Array<readonly Foo>?
- Have thus far decided no.
- Could create an
immutable type operator
- Q: Couldn't you implement that with mapped types?
- May be a bit confusing since state could be captured outside of current object
-
In --strictReadonly mode, this readonly operator would work as described above.
readonly T not assignable to T.
readonly props would not be assignable to mutable props.
readonly T removes mutating methods
-
Outside of strictReadonly, readonly T is just Readonly<T>
-
All of this means that library authors would need to enable readonly mode.
-
Would TypeScript be able to infer whether a method is readonly or not?
- Kind of tricky, methods transitively call each other.
-
How bad are strict variance modes without this?
- Special hell for passing callbacks.
- Need a
super constraint for generics - otherwise many types stay invariant by virtue of taking a T as an input position.
-
Will people know how to use this: readonly?
- Seems like people will always need to be mindful of this when they write
.d.ts files.
- How will we generate this for the DOM if the metadata isn't present? What about
readonly HTMLElement?
-
How do this: readonly parameters work with overloads?
- Currently, if any overloads are not declared with
this: readonly, the property is eliminated.
- That's not going to play well with libraries.
f# Readonly on Exports from Namespaces (#16720)
Readonly & Variance
One thing that comes up quite a bit is strict variance.
If we enabled stricter variance, that would imply that
Arraybecomes invariant.ReadonlyArray.TandReadonlyTStrict variance is easy to enable, but would be hard to make easy to use.
This leads us to start thinking about how to quickly make a readonly version of a type.
We've had an experimental type operator called
readonlykeyof T, you just writereadonly T.Like the
Readonlymapped type, it makes all propertiesreadonlyas well.Readonly<T>mapped type doesn't eliminate mutating methods at all.This means we needed to add a way to indicate that a method doesn't mutate its object.
this: readonlysyntax.Example:
What about deep readonly?
readonly Foo[]give you areadonly Array<readonly Foo>?immutabletype operatorIn
--strictReadonlymode, thisreadonlyoperator would work as described above.readonly Tnot assignable toT.readonlyprops would not be assignable to mutable props.readonly Tremoves mutating methodsOutside of
strictReadonly,readonly Tis justReadonly<T>All of this means that library authors would need to enable readonly mode.
Would TypeScript be able to infer whether a method is readonly or not?
How bad are strict variance modes without this?
superconstraint for generics - otherwise many types stay invariant by virtue of taking aTas an input position.Will people know how to use
this: readonly?.d.tsfiles.readonly HTMLElement?How do
this: readonlyparameters work with overloads?this: readonly, the property is eliminated.