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

[Proposal] Instance variable initialization on class constructor #32820

Closed
ConsoleTVs opened this issue Aug 12, 2019 · 4 comments

Comments

@ConsoleTVs
Copy link

commented Aug 12, 2019

Proposal and Use Cases

When writing a class constructor it's very common to end up with a lot of member assignments that when they get long enough, they add unnecessary lines of code. For instance, an example class constructor may end up looking like:

class Point {
  protected x: number
  protected y: number

  constructor(x: number, y: number) {
    this.x = x
    this.y = y
    console.log(`x: ${this.x}, y: ${this.y}`)
  }
}

const my_point = new Point(5, 10)

This pattern has already been identified and addressed in other programming languages like C++ or Dart. This proposal suggests a way to eliminate it.

The proposed solution is to use the constructor parameters to determine what's assigned to the member by using the known keyword this. This is how the Dart Programming Language manages to eliminate this pattern. Dart acknowledges this with the following statement:

The pattern of assigning a constructor argument to an instance variable is so common.

Following the same example provided above and by using this new proposed solution, the class constructor would look like:

class Point {
  protected x: number
  protected y: number

  constructor(this.x, this.y) {
    console.log(`x: ${this.x}, y: ${this.y}`)
  }
}

const my_point = new Point(5, 10)

Since the parameters reference the class member, there's no need to specify the type either, since it can be inferred by looking at the member's type. Their value is initialized / known prior to the execution of the body of the constructor (if any).

Additionally, the body of the function can be omitted resulting in:

class Point {
  protected x: number
  protected y: number

  constructor(this.x, this.y)
}

const my_point = new Point(5, 10)

Notice, that in case of a default initialization it just needs a =.

class Point {
  protected x: number
  protected y: number

  constructor(this.x = 0, this.y = 0)
}

const my_point = new Point()

More Information

Check the original source in the Dart documentation: https://dart.dev/guides/language/language-tour#constructors

What about parameter properties?

They are really bad for code commenting. Things like:

class Point {
  /**
   * Represents the x cordinate.
   *
   * @type {number}
   * @memberof Point 
   */
  protected x: number

  /**
   * Represents the y cordinate.
   *
   * @type {number}
   * @memberof Point 
   */
  protected y: number

  /**
   * Creates an instance of A.
   * 
   * @param {number} x
   * @param {number} y
   * @memberof Point 
   */
  constructor(this.x = 0, this.y = 0)
}

const my_point = new Point()

Can't be done with:

class Point {
  /**
   * Creates an instance of B.
   * 
   * @param {number} x
   * @param {number} y
   * @memberof Point
   */
  constructor(public x: number = 0, public y: number = 0) {}
}

const my_point = new Point()

Also, the body must be explicitly declared with {}.

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.
@ConsoleTVs

This comment has been minimized.

Copy link
Author

commented Aug 12, 2019

In case this is something weird for some of you, this is another possible solution, cleaner than the original but messier than the proposed one:

class Point {
  protected x: number
  protected y: number

  constructor(x: number, y: number) {
    this.{ x: x, y: y }
    console.log(`x: ${this.x}, y: ${this.y}`)
  }
}

const my_point = new Point(5, 10)
@RyanCavanaugh

This comment has been minimized.

Copy link
Member

commented Aug 12, 2019

This is already well-supported with parameter properties: https://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties

@ConsoleTVs

This comment has been minimized.

Copy link
Author

commented Aug 12, 2019

I will edit my proposal, since the current parameter props are really bad for code commenting.

EDIT: @RyanCavanaugh I've edited the original message!

@RyanCavanaugh

This comment has been minimized.

Copy link
Member

commented Aug 12, 2019

We're trying really hard to avoid adding new expression-level syntax like this (it should go through the TC39 committee), and wouldn't add a second syntax for doing the exact same thing either way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.