Borislav Hadzhiev
Thu Mar 17 2022·3 min read
Photo by Loubna Benamer
You can set default values for class properties directly on the class, e.g.
class Employee {id = 0;}
. When you instantiate the class with the new
operator, you will have access to the default value for the specific property
and you have the ability to change it later on.
class Employee { id = 0; name = 'James Doe'; country = 'Germany'; tasks: string[] = []; vacation: { summer: boolean; winter: boolean; } = { summer: false, winter: false, }; } const emp1 = new Employee(); emp1.id = 701; emp1.name = 'Alice'; emp1.country = 'Austria'; emp1.tasks = ['web dev', 'design']; emp1.vacation = { summer: true, winter: false, }; // 👇️ {id: 701, name: 'Alice', country: 'Austria', ...} console.log(emp1);
We created an Employee
class with
default values for various properties.
TypeScript is able to infer the type of the id
, name
and country
properties based on the default values we provided.
However, if you specify a default value that is an empty array, TypeScript
infers its type to be never[]
, in other words, an array that will always be
empty.
All of the initial values can be changed by creating an instance of the class and changing the properties on the specific instance.
An alternative approach is to provide default values in the constructor method of the class.
class Employee { constructor( public id = 0, public name = 'James Doe', public tasks: string[] = [], ) { this.id = id; this.name = name; this.tasks = tasks; } } const emp1 = new Employee(undefined, undefined, ['accounting']); emp1.id = 100; // 👇️ {id: 100, name: 'James Doe', tasks: ['accounting']} console.log(emp1);
We provided default value for the classes' properties directly in the constructor.
You would use this approach if you need to override the defaults when
instantiating the class with the new
operator.
undefined
when instantiating the class.Note that you must explicitly type any of the classes' properties or parameters that you don't set a default value for.
class Employee { constructor( public id: number, public name = 'James Doe', public tasks: string[] = [], ) { this.id = id; this.name = name; this.tasks = tasks; } } const emp1 = new Employee(100, undefined, ['accounting']);
The id
parameter does not have a default value set, so we must explicitly type
it as number
.
When using this approach with classes that take an object as a parameter, the syntax is a bit more confusing.
class Employee { id: number; name: string; tasks: string[]; vacation: { summer: boolean; winter: boolean; }; constructor( { id, name, tasks, vacation } = { id: 0, name: 'James Doe', tasks: [], vacation: { summer: false, winter: false }, }, ) { this.id = id; this.name = name; this.tasks = tasks; this.vacation = vacation; } } const emp1 = new Employee(); // 👇️ Employee {id: 0, name: 'James Doe', tasks: []} console.log(emp1); emp1.id = 100; emp1.name = 'Alice'; emp1.tasks = ['web dev', 'design']; emp1.vacation.summer = true; // 👇️ {id: 100, name: 'Alice', tasks: ['web dev', 'design'], ...} console.log(emp1);
When you have an object parameter in a class constructor, things become a bit harder to read.
This is why I prefer sticking to multiple, comma-separated parameters. We don't have to remember the parameter order when instantiating the class because any modern IDE shows us which parameter we are on, and which we need to provide next.