Learn TypeScript
Working with standard JavaScript classes
Working with standard JavaScript classes
In this lesson, we will learn how we can work with the standard Javascript features of classes in a strongly-typed manner in TypeScript.
Implementing fields
Let's explore a basic class by carrying out the following steps:
- Open the TypeScript playground by clicking the link below:
- Make sure the TypeScript version in the Playground is set to at least v4 and paste the code from below:
class Product { name; price;}
The code contains a basic class for a product containing fields for the name and price of the product.
What is the inferred type given to the name
and price
fields?
We can add type annotations to class fields using the syntax that we are now familiar with.
- Let's add type annotations to the
name
andprice
fields so thatname
can be any string and theprice
must be numeric:
class Product { name: string; price: number;}
A type error occurs in both of these fields. What is the reason for the error?
In TypeScript, if strict mode is on, fields must be given an initial value or be optional
- Resolve the error by making the fields optional.
- Create a
table1
variable that will be an instance of our class:
const table1 = new Product();
- Assign the following values to the class instance fields:
table1.name = "Table1";table1.price = "$300";
Is a type error raised on any of the assignments? If so, change the assignment(s) so that no type error occurs.
Implementing methods
We can also add strongly-typed methods to classes.
- Let's add the following
copy
method to our class:
class Product { ... copy(name) { const copiedProduct = new Product(); copiedProduct.name = name; copiedProduct.price = this.price; return copiedProduct }}
The method creates a new Product
instance with the specified name with the price from the current instance.
- The method's
name
parameter isn't strongly-typed yet. Add a type annotation to ensure this is a string.
- Create a
table2
variable assigned to the copy of thetable1
product with the name'Table2'
.
Notice the intellisense as you enter the code.
Nice!
Implementing constructors
We are going to force the product's name and price to be specified when it is instantiated.
- Remove the optional flag from the
name
andprice
fields and add a constructor to initalize these:
class Product { name: string; price: number; constructor(name, price) { this.name = name; this.price = price; } ...}
- The constructor parameters aren't strongly-typed yet. Add type annotations to ensure
name
is a string, andprice
is a number.
- The
copy
method now has a type error becauseProduct
is instantiated without aname
orprice
. Resolve this error.
- Resolve a similar type error with the
table1
variable assignment.
That was great how TypeScript helped us refactor our class implementation and resolve breakages in consuming code.
Property inference from constructors
- Let's remove the type annotations on the property:
class Product { name; price; ...}
What has TypeScript inferred the types on these properties to be?
Wow, TypeScript has cleverly inferred the types of the properties from the assignments in the constructor!
This was added in TypeScript 4.0. In previous versions the types will inferred to be any
.
Implementing static classes
We will enhance our Product
to include a static method to check whether products are equal.
- Add the following static
equal
method to our class:
class Product { ... static equal(product1, product2) { return product1.name === product2.name && product1.price === product2.price; }}
- The method isn't strongly-typed yet. Add type annotations to the parameters to make it strongly-typed.
- Use the static method to check whether our
table1
andtable2
products are equal.
Classes v type aliases v interfaces
Classes create object structures like type aliases and interfaces do. A key difference is that a class contains method implementation, whereas type aliases and interfaces don't. Classes can also be instantiated and execute logic during this process. Type aliases and interfaces can't be instantiated because they only contain structural information.
So, a class is useful for representing an object blueprint that contains constructor and method implementation.
Summary
Classes can be made strongly-typed by adding type annotations to constructor parameters, fields, and method parameters. Alternatively, the type for constructor parameters, fields, and method parameters can be inferred if they are assigned to values in their declaration.
Fields and parameters can be made optional using a question mark (?
) before their type annotation.
In the next lesson, we will learn how we can control the access that consumers have to class members.