Understanding TypeScript’s Type System

A type system is a set of rules that assigns a type to every variables, expression, class, function, object, or module in the system.

These rules are checked against to expose errors in a program and can be performed at compile time (static type checking) or at runtime (dynamic type checking).

JavaScript Type SystemJavaScript is dynamically typed and therefore variables have no associated types.

As mentioned above, you can assign a value of one type to a variable and later assign a value of a different type to the same variable.

The problem with this is that operations with incompatible types can produce unpredictable results in our software.

The benefit of JavaScript’s type system is its flexibility, which can also lead to other issues as I have already stated.

// Assignment of different typeslet date = '10/10/1991'; date = 10101991;TypeScript Type SystemTypeScript’s system provides for specifying and inferring types, as well as setting types as optional.

The optional setting allows you to choose when to enforce types and when to allow dynamic types.

To opt out of type checking, you can use the any keyword.

TypeScript is statically typed, therefore, all checks are performed at compile time.

The compiler checks all variables and expressions against their types, and removes all type information when it converts the code into valid JavaScript.

// Assignment of different typeslet date = '10/10/1991'; date = 10101991; // Results in a TypeScript compiler errorTypeScript’s Structural Type SystemA type system is either structural or nominal, and in some cases it may have a mix of both within in a single type system (i.

e.

Flow).

TypeScript is structurally typed, unlike most C-like languages which have a nominative type system.

In a structural type system, two types are deemed the same if they have the same structure.

So the explicit decoration is not required.

A value is acceptable if its structure matches that of the required type.

class Foo { method(input: string) { /* .

*/ } }class Bar { method(input: string) { /* .

*/ } }let foo: Foo = new Bar(); // Works!The example above works because even though Foo and Bar have different names, they have the exact same structure.

If this shape/structure changes, it will result in errors.

class Foo { method(input: string) { /* .

*/ } }class Bar { method(input: number) { /* .

*/ } }let foo: Foo = new Bar(); // Error!In a nominal, or nominative, type system, two types are considered to be the same if they have the same name.

It relies on explicit annotations to determine types.

class Foo { method(input: string) { /* .

*/ } }class Bar { method(input: string) { /* .

*/ } }let foo: Foo = new Bar(); // Error!The above example results in an error because they have different names.

A nominal type system is intended to prevent accidental type equivalence which means just because something has the same properties does not mean it is valid.

TypeScript, on the other hand, is structurally typed and accidental type equivalence is possible.

In a nominal type system you could use named types to ensure that correct arguments were being passed.

Structural typing complements the type inference in TypeScript.

Thanks to features such as these, you can leave most of the work to the compiler and language service, rather than having to explicitly add type information and class heritage throughout your program.

Type ErasureEver wondered what happens behind the scenes when the tsc command is run?.You are obviously familiar with the part where TypeScript will compile and generate plain JavaScript code, but the newly generated code is different in the following ways:Code transformation — Code transformation converts the language features that are no available in JavaScript into representations that are available and valid.

An example of this is if you are targeting ECMAScript 5 where classes are not available, all classes will be converted into JavaScript functions that create appropriate representations using the prototypal inheritance found in ECMAScript 5.

Type erasure — Type erasure is the process by which all of the type annotations from are removed or ‘erased’ as the name implies because they are not understood by JavaScript.

The type annotations and interfaces are required at development and compile time for static type checking but at runtime the types are not checked.

TypeScript codeclass OrderedArray<T> { private items: T[] = []; constructor(private comparer?: (a: T, b: T) => number) { } add(item: T): void { this.

items.

push(item); this.

items.

sort(this.

comparer);} getItem(index: number) : T { if (this.

items.

length > index) { return this.

items[index]; } return null; }}var orderedArray: OrderedArray<number> = new OrderedArray<number>();orderedArray.

add(5);orderedArray.

add(1);orderedArray.

add(3);var firstItem: number = orderedArray.

getItem(0);alert(firstItem); // 1Compiled JavaScript codevar OrderedArray = (function () { function OrderedArray(comparer) { this.

comparer = comparer; this.

items = []; } OrderedArray.

prototype.

add = function (item) { this.

items.

push(item); this.

items.

sort(this.

comparer);};OrderedArray.

prototype.

getItem = function (index) { if (this.

items.

length > index) { return this.

items[index]; } return null; }; return OrderedArray;})();var orderedArray = new OrderedArray();orderedArray.

add(5);orderedArray.

add(1);orderedArray.

add(3);var firstItem = orderedArray.

getItem(0);alert(firstItem); // 1Type InferenceYou may have guessed what this process entails because the name gives it away.

One thing is for sure, it has nothing to do with what takes place in Type Erasure.

Alright, so what is it?.It’s the process in which types are determined at compile time in the absence of explicit type annotations.

That being said…The main takeaway is to understand that TypeScript’s type system is structural.

Structural typing can make some designs quite complex, but that doesn’t prevent you from using any patterns that you may wish to transfer from a nominally typed system.

Furthermore, structural typing allows you to exclude explicit type annotations.

As a result, the types will be inferred.

Finally, when the TypeScript program is compiled, the types are checked against the explicit and implicit types, where any errors can be detected at compile time.

References & Further Reading:Pro TypeScript – Application-Scale JavaScript Development | Steve Fenton | ApressJavaScript is everywhere, both as a pure language and in popular libraries like Angular, jQuery and Knockout, but users…www.

apress.

comNominal & Structural Typing | FlowDifferences between nominal and structural typingflow.

orgType Systems: Structural vs.

Nominal typing explainedPlease do not link to this article on Reddit or Hacker News.

medium.

comThe State of JavaScript 2018: JavaScript Flavors – TypeScriptDiscover the most popular JavaScript technologies of the year.

2018.

stateofjs.

com.. More details

Leave a Reply