Is there any way to assign the class member properties default values if they are omitted by the user?
I have a custom class that constains an optional instance of another class:
export class MyClass1 {
constructor() {
this.name = "";
this.classInstance = new MyClass2();
}
name: string; // name of the object
classInstance?: MyClass2;
}
class MyClass2 {
constructor() {
this.name = "MyClass2 initial name";
}
name: string;
}
The content for MyClass1 comes from JSON, so some sometimes the member variable classInstance can be undefined. In these cases I'd like the MyClass1 constructor to initiate new MyClass2() into classInstance member variable.
This is how I assign create the instance of MyClass1:
let myNewClass: MyClass1 = {
name: "MyClass"
}
Because the classInstance is omitted, I assumed it would have the default value set in the constructor. However, this is not the case. I also tried removing the optional sign from the classInstance-variable, but this gives a compilation error because then the object has to match the structure of MyClass1. I guess I managed to compile without errors by casting, but it didn't solve the problem (although I'm not sure if this compiled properly either):
let myNewClass: MyClass1 = {
name: "MyClass"
} as MyClass1
In neither case did classInstance get the default value that the constructor sets, it came out null/undefined.
For me it doesn't matter how the casting problem is solved (whether to set properties optional or use casting), as long as I have control over the default values.
解决方案
The problem here is
let myNewClass: MyClass1 = {
name: "MyClass"
} as MyClass1
here is not MyClass1 instance. TypeScript type system was 'cheated' to think that plain object is MyClass1 instance.
It will be transpiled to var myNewClass = { name: "MyClass" }. MyClass1 class isn't instantiated. End of the story.
The proper recipe to do the expected thing is providing values from JSON to class constructor. Considering that object properties (classInstance) can be undefined, class properties can't rely on default values like constructor({ classInstance = new MyClass2 }) { ... } and should be assigned manually:
export class MyClass1 {
constructor(jsonMyClass1: MyClass1 = {}) {
const { name, classInstance } = jsonMyClass1;
this.name = 'name' in jsonMyClass1 ? name : "";
this.classInstance = 'classInstance' in jsonMyClass1 ? classInstance : new MyClass2;
}
name: string;
classInstance?: MyClass2;
}
let myNewClass: MyClass1 = new MyClass1({
name: "MyClass"
});
When data is supplied and processed with how it will be consumed by the classes in mind (i.e. using null exclusively for values that are not defined), the recipe can be modified to use the powers offered by the language:
export class MyClass1 {
constructor(jsonMyClass1: MyClass1 = {} as MyClass1) {
const { name = "", classInstance = new MyClass2 } = jsonMyClass1;
this.name = name;
this.classInstance = classInstance;
}
name: string;
classInstance: MyClass2;
}
let myNewClass: MyClass1 = new MyClass1({
name: "MyClass",
classInstance: null
});