Open OldStarchy opened 6 months ago
We're considering closing the { readonly x: number }
-> { x: number }
soundness hole under a flag, at which point you'd be able to express this solely in terms of existing operations, e.g.
class Point
readonly x: number;
readonly y: number;
modify(this: Mutable<Point>, x: number, y: number) {
}
}
Related: #35313
class Point {
readonly x: number;
readonly y: number;
modify(this: Mutable<Point>, x: number, y: number) {
this.x = x;
this.y = y;
}
}
const p = new Point(0, 0);
p.modify(3, 4); // error? (argument of type Point is not assignable to type Mutable<Point>)
const q = p as Mutable<Point>; // then wouldn't this also error with the same type conversion?
q.modify(3, 4);
// and if not, then i could also do this
function badFunc(point: Point) {
(point as Mutable<Point>).modify(3, 4);
}
Is this what you're intending?
I was thinking recently that I do prefer rust's style of const-by-default, but with this syntax I'm not sure the correct way to create something mutable.
I just realized I didn't specify this explicitly, but ideally the "const" flag would work for any parameter of any function
function createConvexHull(const poly: Polygon): Polygon {
//...
}
π Search Terms
const method parameter keyword readonly class C++ like const methods class method with const keyword "as const" for class type
β Viability Checklist
β Suggestion
I'm sure I've seen this suggestion somewhere before but I couldn't find ithttps://github.com/microsoft/TypeScript/issues/35313Allow using
as const
on class objects by annotating methods asconst
(syntax tbd).A const method would (like in C++) not allow modifying properties of
this
or calling any method not also marked asconst
.An object marked with
as const
would similarly be readonly and only methods marked asconst
would be callable.π Motivating Example
Keeping track of mutable vs immutable can be tricky when you're not used to the library you're using (or if its poorly written). It's very important to get it right in many libraries (
react
state,vue
refs (shallow vs deep),preact/signals
) where modifying values may or may not be required.Debugging mutability bugs can be a pain sometimes too
Declaration syntax 1 using a
const
decorationDeclaration syntax 2 using
this: const
parameterI personally much prefer the first syntax where
const
is a decoration.Parameter syntax 1
Not to be confused with
(as an aside a more appropriate syntax for that would be
foo(const p: Point)
orfoo(const p: const Point)
but that's OoS)Parameter syntax 2
Again I prefer syntax 1. The const type inference needs to happen in the compiler, making it look like a utility type would be confusing. The use of
const
also mirrors the declaration syntax 1.The inference of the new readonly type should :tm: be simple enough, convert any r/w properties to readonly, and remove any functions not marked as const.
For simplicity arrow method properties should be handled as any other property would.
The reason I suggest this is only because there needs to be a line drawn somewhere as to how complex this feature becomes. As mentioned in TypeScripts third non-goal this is a tradeoff between usefulness and simplicity.
Its already possible to break the type system and its up to the programmers to not do stupid things.
Other types
π» Use Cases
What workarounds are you using in the meantime? Manually defining a
ReadonlyPoint
variation and casting to it.