Skip to content
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

Type-mutating functions #27568

Closed
apirila opened this issue Oct 5, 2018 · 5 comments
Closed

Type-mutating functions #27568

apirila opened this issue Oct 5, 2018 · 5 comments
Labels
Duplicate An existing issue was already created

Comments

@apirila
Copy link

apirila commented Oct 5, 2018

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)
@jack-williams
Copy link
Collaborator

Related: #25679 #8655

@DanielRosenwasser DanielRosenwasser added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Oct 5, 2018
@DanielRosenwasser
Copy link
Member

Also #10421.

@DanielRosenwasser DanielRosenwasser changed the title Decorator Functions Type-mutating functions Oct 5, 2018
@RyanCavanaugh RyanCavanaugh added Duplicate An existing issue was already created and removed In Discussion Not yet reached consensus Suggestion An idea for TypeScript labels Oct 9, 2018
@RyanCavanaugh
Copy link
Member

Effectively the same as #10421

@mpawelski
Copy link

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.

@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
Copy link
Member

We think it's very valuable, but have no ideas on how to implement it without completely blowing up performance

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

5 participants