After completing the second edition of the book “Angular Development with TypeScript“, my colleague Anton Moiseev and I started working on yet another book for Manning. This one will be called “TypeScript Quickly” and its tentative Table of Contents is available here.
This book will cover the main syntax elements of the TypeScript language, and to make the book more interesting, we’ll also develop a blockchain app.
Meanwhile, I’ll start a series of blogs on the TypeScript-related topics. This one is about TypeScript’s structural type system.
A primitive type has just a name (e.g. number) while a more complex type like an object or class has a name and some structure represented by properties (e.g. a class Customer has properties name and address).
How would you know if two types are the same or not? In some languages (e.g. Java) two types are the same if they have the same names, which represents a nominal type system. In Java, the last wouldn’t compile because the names of the classes are not the same even though they have the same structure:
class Person { String name; } class Customer { String name; } Customer cust = new Person(); // compiler's error
But TypeScript and some other languages use the structural type system. In the following code snippet I re-wrote the above code snippet in TypeScript:
class Person { name: string; } class Customer { name: string; } const cust: Customer = new Person(); // no errors
This code doesn’t report any errors because TypeScript uses structural type systems, and since both classes Person and Customer have the same structure, it’s OK to assign an instance of one class to a variable of another.
Moreover, you can use object literals to create objects and assign them to class-typed variables or constants as long as the shape of the object literal is the same. The following code snippet will compile without errors:
class Person { name: string; } class Customer { name: string; } const cust: Customer = { name: 'Mary' }; const pers: Person = { name: 'John' };
Our classes didn’t define any methods, but if both of them would define a method(s) that has the same signature (name, arguments, and the return type) they would also be compatible.
What if the structure of Person and Customer are not exactly the same? Let’s add a property age to the class Person as is the following listing:
class Person { name: string; age: number; // 1 } class Customer { name: string; } const cust: Customer = new Person(); // still no errors
1 We’ve added this property
Still no errors! TypeScript sees that Person and Customer have the same shape. We want to use the constant of type Customer (it has the property name) to point at the object of type Person (it also has the property name).
Follows the link https://bit.ly/2MbHvpH and you’ll see this code in TypeScript playground (a REPL to try code snippets in TypeScript and compile them into JavaScript). Click Ctrl-Space after the dot in cust. and you’ll see that only the name property is available even though the class Person has also the property age.
Homework: Can the class Customer have more properties than Person?
In the previous code snippet, the class Person had more properties than Customer and the code compiled without errors. What if the class Customer has more properties than Person? Would the following code compile? Explain your answer.
class Person { name: string; } class Customer { name: string; age: number; } const cust: Customer = new Person();
As they say, “If it walks like a duck and it quacks like a duck, then it must be a duck”. That’s why structural typing is also known as duck typing. If an object can be used for a particular purpose, use it. Yes, it’s not a duck, but at least it walks like a duck, which is all that matters in this context.
It is a bit discouraging after Java.