Skip to content

Type-mutating functions #27568

Closed
Closed

Description

@apirila

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

  1. jack-williams commented on Oct 5, 2018

    @jack-williams
    Collaborator

    Related: #25679 #8655

  2. DanielRosenwasser commented on Oct 5, 2018

    @DanielRosenwasser
    Member

    Also #10421.

  3. changed the title [-]Decorator Functions[/-] [+]Type-mutating functions[/+] on Oct 5, 2018
  4. RyanCavanaugh commented on Oct 9, 2018

    @RyanCavanaugh
    Member

    Effectively the same as #10421

  5. mpawelski commented on Oct 10, 2018

    @mpawelski

    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"? 😜

  6. RyanCavanaugh commented on Oct 10, 2018

    @RyanCavanaugh
    Member

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

  7. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions