So its necessary [to specificy null on] both on the constructor and the field definition?
Yes, but only because of how the managerOf it's declared. It all flows from the type of the property, and Typescript enforces that the rest must match.
You declared it:
private managerOf: User;
Which means only a User is a valid type to be assined to managerOf. null is not a User so is not allowed.
Now you go to the constructor:
class User {
private name: string;
private managerOf: User;
constructor(name: string, managerOf: User) {
this.name = name;
this.managerOf = managerOf;
}
}
new User('qwerty', null) // error
Here you can't pass in null because the constructor doesn't allow null there. So let's fix that:
class User {
private name: string;
private managerOf: User;
constructor(name: string, managerOf: User | null) {
this.name = name;
this.managerOf = managerOf; // error
}
}
new User('qwerty', null) // fine
Now you can pass null to the constructor, but null still isn't an allowed type for the memberOf property, so you get an error when you try to do that assignment.
So now let's allow the property to null:
class User {
private name: string;
private managerOf: User | null;
constructor(name: string, managerOf: User | null) {
this.name = name;
this.managerOf = managerOf; // fine
}
}
new User('qwerty', null) // fine
So, if the property memberOf is allowed to be null then that needs to part of the type.
And the memberOf constructor argument is totally separate from the memberOf property of the class instances. The only thing that links them is that you decide to assign one to the other, and Typescript enforces type safety in that assignment.
How's typescript supposed to know that you don't want to do something like this?
class User {
private name: string,
private managerOf: User
constructor(name: string, managerOf: User | null) {
this.name = name
this.managerOf = managerOf || defaultManager
}
}
const jerry = new User("Jerry", null);
jerry.managerOf.name // returns the default name
Here you accept null in the constructor, but the proeprty can't be null and is populated with a default value.
Cases like this are why you have to put it "both" places.
It's worth noting there is a common shorthand for this:
class User {
constructor(
private name: string,
private managerOf: User | null
) {}
}
new User('qwerty', null) // fine
This syntax accepts a constructor argument and assigns it to an instance property only ever declaring it once.
See playground
Type 'User | null' is not assignable to type 'User'.managerOfnullable as well? I'm not sure what the problem is.managerOfnullable as well, and why would I need to do that if I specify it being nullable in the constructor.