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
nameandpricefields so thatnamecan be any string and thepricemust 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
table1variable 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
copymethod 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
nameparameter isn't strongly-typed yet. Add a type annotation to ensure this is a string.
- Create a
table2variable assigned to the copy of thetable1product 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
nameandpricefields 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
nameis a string, andpriceis a number.
- The
copymethod now has a type error becauseProductis instantiated without anameorprice. Resolve this error.
- Resolve a similar type error with the
table1variable 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
equalmethod 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
table1andtable2products 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.