Repository navigation
Type-mutating functions #27568
Description
Search Terms
Type guard, assert, decorator
Suggestion
Current type guard support syntax:
interface Rectangle {
x: number;
y: number;
}
interface Cube {
x: number;
y: number;
z: number;
}
function isRectangle(t: Rectangle|null): t is Rectangle {
return !t;
}Consider following function:
function makeCube(t: Rectangle) {
t.z = 1;
}This function changes a type of t to something else by adding a property, but it is not possible to tell to the TypeScript compiler that it does so. I propose that a new syntax is added:
function makeCube(t: Rectangle): t as Cube {
(t as Cube).z = 1;
}After that the compiler would know that the the parameter given to the function hasd been mutated from one type to another. This would obviously work only for objects. After the change this would work:
function foo() {
let t: Rectangle = {x: 1, y: 1};
makeCube(t);
console.log(t.z); /* <= Here the type of t would be cube. */
}Type guard can used for similar behavior. But the return statement in makeCube and the if statement feels unneeded.
function makeCube(t: Rectangle): t is Cube {
(t as Cube).z = 1;
return true;
}
function foo() {
let t: Rectangle = {x: 1, y: 1};
íf (makeCube(t)) {
console.log(t.z); /* <= Here the type of t is cube. */
}
}Use Cases
This functionality could be used for implementing asserts, e.g. Assert.isNotNull which would make unit test environments easier if strict null checks are used. If you have a type T|null, then that could be mutated to T.
E.g.
function isNotNull<T>(o: T|null): o as T {
if (!o) throw new Error("o is null");
}Another use case is decorator pattern. The decorator could add more properties to an object and hence change the type of it.
Examples
See suggestion section.
Checklist
My suggestion meets these guidelines:
- [Y] This wouldn't be a breaking change in existing TypeScript / JavaScript code
- [Y] This wouldn't change the runtime behavior of existing JavaScript code
- [Y] This could be implemented without emitting different JS based on the types of the expressions
- [Y] This isn't a runtime feature (e.g. new expression-level syntax)
Activity
jack-williams commentedon Oct 5, 2018
Related: #25679 #8655
DanielRosenwasser commentedon Oct 5, 2018
Also #10421.
[-]Decorator Functions[/-][+]Type-mutating functions[/+]RyanCavanaugh commentedon Oct 9, 2018
Effectively the same as #10421
mpawelski commentedon Oct 10, 2018
This seems like a nice feature to have that can model a lot of old "mixin" style code that was/is used in JS code. Even for more modern code it would be useful (like mentioned assert functions).
I personally had situation when I was migrating old code to TS and this feature would allow me to just annotate function that modified type of passed object. I had to change the function and caller code to use new object returned by this function. It wasn't a big issue in this case but slowed down a bit migration to TS.
Ryan Cavanaugh (@RyanCavanaugh) Can you tell a bit more why it was rejected in Suggestion Backlog Slog? Your comment "No control flow nodes to attach this to" doesn't tell me much 🙁 Does it mean "Not easy to implement and this feature doesn't seem that valuable"? 😜
RyanCavanaugh commentedon Oct 10, 2018
We think it's very valuable, but have no ideas on how to implement it without completely blowing up performance