Skip to content

Init class instance in one line and respect default values with DRY principle #27968

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

Closed
3 tasks done
weber-d opened this issue Oct 18, 2018 · 3 comments
Closed
3 tasks done
Labels
Duplicate An existing issue was already created External Relates to another program, environment, or user action which we cannot control.

Comments

@weber-d
Copy link

weber-d commented Oct 18, 2018

Search Terms

One line init, initialize class like c#,set default attribute values, Init class in single line

Suggestion

I want to have a quick way to how we can initialize multiple attributes of a class without redundant call of the main object. This is already possible, but it's a bit hard to respect default values of the class, without re-assign them.

Use Cases

In my case I have a simply model class which width attribute. This class is indent for configuration purpose, so it's mainly used in my configuration object (which is based on TypeScript, too). Per default, the width should be 100%, cause this is set for about 90% of the (array element) config entrys of this type. Some of them should be able to override this.

Respecting the DRY pattern, I don't want repeat the 100% width for all default elements, so I set this as default in the corresponding class attribute. So it seems that this can only be realized using Partial<T> in the constructor, which isn't as handy as the default initialization in high level languages like C#.

Apart from that, I see this is not a uncommon requirement for clean code. Initializing a class by respecting their default propertys can be usefull especially when having larger classes. For example when they need got mapped with data from different sources.

Examples

See the following C# code:

class MyTest {
  public string Field1{ get; set; }
  public string Field2{ get; set; } = "DefaultValue";
}

If we declare a new instance of MyTest and initialize the Field1 property

var test = new MyTest() {
  Field1 = "Test"
};

Now test.Field1 is Test and test.Field2 has the default value of DefaultValue defined in MyTest. That's a smart and intuitive syntax. If we want a similar behavior in TypeScript, that's more complicated. Having a simple model:

export class MyClass {
  Field1: string = ""
  Field2: string = "DefaultValue"
}

it's not possible to initialize it with a custom Field1 value and leave Field2 to it's default value like this:

let test: MyClass = {Field1: 'Test'}
// Error: Property "Field" is missing in type

This is only possible when ALL fields are set

let test: MyClass = {Field1: 'Test', Field2: "DefaultValue"}

which is clearly bad practice cause we've more code as needed and mainly those default values need to be present on EVERY object of this class which is created. So the default value may widely spread, when it is commonly used together with those class.

To avoid this, we need the following overhead:

export class MyClass {
  Field1: string = ""
  Field2: string = "DefaultValue"

  public constructor(init: Partial<MyClass>) {
    Object.assign(this, init)
  }
}

let test = new MyClass({ Field1: "Test" })
// MyClass {Field1: "Test", Field2: "DefaultValue"}

Works as expected, but is overhead and lead into wrong intellisense suggestions of VS code: It shows both Field1 and Field2 as nullable. In general this is correct, they MAY be nullable if we don't pass any parameter cause the Partial<T> usage doesn't force us to initialize all propertys. But this can be misleading if we have a real nullable property like

export class MyTest {
    NotNullableField: int
    NullableField: int?
    // ...
   public constructor(init: Partial<MyClass>) {
       Object.assign(this, init)
   }
}

both were displayed as nullable in the constructor, alhough only the second one really is.

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. new expression-level syntax)
@ghost
Copy link

ghost commented Oct 18, 2018

Duplicate of #13195 ?

@weswigham
Copy link
Member

Aye; I'll call the part we can do - improving the type on the constructor for less misleading types - a duplicate of #13195. New expression-level syntax for c#-y class initialization should be directed to the tc39 committee for JS itself, as we do not add new expression level syntax without it being a late-stage JS proposal anymore.

@weswigham weswigham added Duplicate An existing issue was already created External Relates to another program, environment, or user action which we cannot control. labels Oct 18, 2018
@RyanCavanaugh
Copy link
Member

Also related #16737 / #3895

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 External Relates to another program, environment, or user action which we cannot control.
Projects
None yet
Development

No branches or pull requests

3 participants