Typescript: Difference between revisions

From Training Material
Jump to navigation Jump to search
 
mNo edit summary
Line 13: Line 13:
{{Can I use your material}}
{{Can I use your material}}


== Introduction ==
== Introduction ==


* Created by Microsoft
* Created by Microsoft
Line 23: Line 23:
** Dynamic module loading at runtime
** Dynamic module loading at runtime


=== Intro con't ===  
=== Intro con't ===  


* Typed superset of JavaScript
* Typed superset of JavaScript
Line 33: Line 33:
*** And even in native applications on operating systems that expose a JavaScript API (WinJS, Web APIs)
*** And even in native applications on operating systems that expose a JavaScript API (WinJS, Web APIs)


=== Intro con't 1 ===  
=== Intro con't 1 ===  


* TypeScript language feature sources
* TypeScript language feature sources
Line 41: Line 41:
* All of the TypeScript features can be converted into valid ECMAScript 5
* All of the TypeScript features can be converted into valid ECMAScript 5


=== Intro con't 2 ===  
=== Intro con't 2 ===  


* Can consume the existing libraries and frameworks written in JavaScript
* Can consume the existing libraries and frameworks written in JavaScript
Line 49: Line 49:
** The generated JavaScript correlates closely to the original TypeScript code
** The generated JavaScript correlates closely to the original TypeScript code


=== Intro con't 3 ===
=== Intro con't 3 ===


* Supported within:
* Supported within:
Line 57: Line 57:
** Lots of other popular code editors
** Lots of other popular code editors


== Installing TypeScript ==
== Installing TypeScript ==


* Command line
* Command line
Line 68: Line 68:
* Plugin to: Visual Studio Code, Sublime Text, Eclipse, Vim, etc
* Plugin to: Visual Studio Code, Sublime Text, Eclipse, Vim, etc


== Preparing a TypeScript project ==
== Preparing a TypeScript project ==


* File ''tsconfig.json''
* File ''tsconfig.json''
Line 78: Line 78:
** <small>https://code.visualstudio.com/docs/languages/typescript</small>
** <small>https://code.visualstudio.com/docs/languages/typescript</small>


== Understanding Typing, Variables, and Functions ==
== Understanding Typing, Variables, and Functions ==


* All of the JavaScript standard control structures are immediately available within a TypeScript program:
* All of the JavaScript standard control structures are immediately available within a TypeScript program:
Line 86: Line 86:
** Subroutines
** Subroutines


=== Transferring JavaScript into TypeScript ===
=== Transferring JavaScript into TypeScript ===


* All JavaScript is valid TypeScript
* All JavaScript is valid TypeScript
Line 96: Line 96:
** Although the code may work, the TypeScript compiler will warn about any potential problems it has detected
** Although the code may work, the TypeScript compiler will warn about any potential problems it has detected


==== Example 1 ====
==== Example 1 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
// Not using with
// Not using with
Line 112: Line 112:
</syntaxhighlight>
</syntaxhighlight>


=== Variables ===
=== Variables ===


* Must follow the JavaScript naming rules
* Must follow the JavaScript naming rules
Line 124: Line 124:
* Simple tester https://mothereff.in/js-variables
* Simple tester https://mothereff.in/js-variables


==== Variables con't ====
==== Variables con't ====


* Variables are functionally scoped
* Variables are functionally scoped
Line 132: Line 132:
** also in its nested contexts
** also in its nested contexts


==== Variables con't 1 ====
==== Variables con't 1 ====


* To create a global variable, declare it without the '''var''' keyword
* To create a global variable, declare it without the '''var''' keyword
Line 140: Line 140:
** which prevents a whole category of hard to diagnose bugs in our code
** which prevents a whole category of hard to diagnose bugs in our code


==== Variables con't 2 ====
==== Variables con't 2 ====


* '''let''' vs old '''var'''
* '''let''' vs old '''var'''
Line 163: Line 163:
</syntaxhighlight>
</syntaxhighlight>


==== Variables con't 3 ====
==== Variables con't 3 ====


* '''const''' declaration<syntaxhighlight lang="ts">const maxTrainingsPerCart = 10;</syntaxhighlight>
* '''const''' declaration<syntaxhighlight lang="ts">const maxTrainingsPerCart = 10;</syntaxhighlight>
Line 184: Line 184:
trainingCartRestrictions.maxTrainingsPerCart--;
trainingCartRestrictions.maxTrainingsPerCart--;
</syntaxhighlight>
</syntaxhighlight>
===== Const for objects, fixes =====
===== Const for objects, fixes =====
* Object.freeze()<syntaxhighlight lang="ts">
* Object.freeze()<syntaxhighlight lang="ts">
const trainingCartRestrictions = Object.freeze({
const trainingCartRestrictions = Object.freeze({
Line 198: Line 198:
</syntaxhighlight>
</syntaxhighlight>


==== Example 2 ====
==== Example 2 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
function subtrNrs(c, d) {
function subtrNrs(c, d) {
Line 210: Line 210:
</syntaxhighlight>
</syntaxhighlight>


=== Types ===
=== Types ===


* TypeScript is optionally statically typed
* TypeScript is optionally statically typed
Line 219: Line 219:
** Static typing allows development tools to provide intelligent auto-completion
** Static typing allows development tools to provide intelligent auto-completion


==== Annotations ====
==== Annotations ====


* TypeScript can infer types automatically
* TypeScript can infer types automatically
Line 228: Line 228:
** For variable, the type annotation comes after the identifier and is preceded by a colon
** For variable, the type annotation comes after the identifier and is preceded by a colon


==== Annotations Con't ====
==== Annotations Con't ====


The type used to specify an annotation can be:
The type used to specify an annotation can be:
Line 237: Line 237:
** No checks are made on dynamic types
** No checks are made on dynamic types


==== Example 3 ====
==== Example 3 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
// primitive type annotation
// primitive type annotation
Line 265: Line 265:
</syntaxhighlight>
</syntaxhighlight>


==== Primitive Types ====
==== Primitive Types ====


* Directly represent the underlying JavaScript types and follow the standards set for those types
* Directly represent the underlying JavaScript types and follow the standards set for those types
Line 276: Line 276:
** equivalent to opting out of type checking for the life of the variable
** equivalent to opting out of type checking for the life of the variable


==== Primitive Types Con't ====
==== Primitive Types Con't ====


Types that refer to the absence of values:
Types that refer to the absence of values:
Line 285: Line 285:
* '''never''' - no return, not even void ( ex. error, infinite loop, exception thrown )
* '''never''' - no return, not even void ( ex. error, infinite loop, exception thrown )


==== Arrays ====
==== Arrays ====


* Have precise typing for their contents
* Have precise typing for their contents
Line 293: Line 293:
** When we access elements in the array, we will get quality auto-completion because the type of each item is known
** When we access elements in the array, we will get quality auto-completion because the type of each item is known


==== Example 4 ====
==== Example 4 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
interface Movie {
interface Movie {
Line 339: Line 339:
</syntaxhighlight>
</syntaxhighlight>


==== Exercise 4 ====
==== Exercise 4 ====
<pre>
<pre>
Describe some Monuments with:
Describe some Monuments with:
Line 390: Line 390:
-->
-->


==== Enumerations ====
==== Enumerations ====


* Represent a collection of named elements  
* Represent a collection of named elements  
Line 400: Line 400:
** To get the identifier name from the enumeration, treat the enumeration like an array
** To get the identifier name from the enumeration, treat the enumeration like an array


==== Enumerations Con't ====
==== Enumerations Con't ====


In TypeScript enumerations are open ended
In TypeScript enumerations are open ended
Line 408: Line 408:
** Useful technique for extending code from third parties, in ambient declarations and from the standard library
** Useful technique for extending code from third parties, in ambient declarations and from the standard library


==== Example 5 ====
==== Example 5 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
enum MusicKind {
enum MusicKind {
Line 439: Line 439:
</syntaxhighlight>
</syntaxhighlight>


==== Exercise 5 ====
==== Exercise 5 ====


<pre>
<pre>
Line 477: Line 477:
-->
-->


==== Assertions ====
==== Assertions ====


Can override the type
Can override the type
Line 487: Line 487:
** We can force a type assertion by adding an additional '''<any>'''
** We can force a type assertion by adding an additional '''<any>'''


==== Example 6 ====
==== Example 6 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
interface Musician {
interface Musician {
Line 523: Line 523:
</syntaxhighlight>
</syntaxhighlight>


==== Exercise 6 ====
==== Exercise 6 ====


<pre>
<pre>
Line 568: Line 568:
-->
-->


==== Operators ====
==== Operators ====


Some JavaScript operators have special significance within TypeScript  
Some JavaScript operators have special significance within TypeScript  
Line 574: Line 574:
* they affect types
* they affect types


===== Increment, Decrement =====
===== Increment, Decrement =====


* Increment (++) and decrement (--) operators can only be applied to variables of type
* Increment (++) and decrement (--) operators can only be applied to variables of type
Line 584: Line 584:
** We can increase and decrease the value beyond the bounds of the enumeration
** We can increase and decrease the value beyond the bounds of the enumeration


===== Example 7 =====
===== Example 7 =====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
enum FootSize {
enum FootSize {
Line 607: Line 607:
</syntaxhighlight>
</syntaxhighlight>


===== Binary Operators =====
===== Binary Operators =====


* Binary operators: - * / % << >> >>> & ^ |
* Binary operators: - * / % << >> >>> & ^ |
Line 615: Line 615:
** The result of an operation in this list is always a '''number'''
** The result of an operation in this list is always a '''number'''


===== Binary Operators Con't =====
===== Binary Operators Con't =====


* The plus (+) operator can be
* The plus (+) operator can be
Line 624: Line 624:
** try to return a '''string''' for a function that is annotated to return a '''number'''
** try to return a '''string''' for a function that is annotated to return a '''number'''


===== Logical Operators =====
===== Logical Operators =====
* NOT - ! inverts, !! converts to BOOLEAN
* NOT - ! inverts, !! converts to BOOLEAN
* AND - &&  
* AND - &&  
Line 631: Line 631:
* Conditional Operator - isOK ? 'Y' : 'N'
* Conditional Operator - isOK ? 'Y' : 'N'


===== Type Operators =====
===== Type Operators =====
* Can assist us when working with objects in JavaScript
* Can assist us when working with objects in JavaScript
* Relevant to working with classes - '''typeof, instanceof, in, delete'''
* Relevant to working with classes - '''typeof, instanceof, in, delete'''


=== Functions ===
=== Functions ===


* In TypeScript most functions are actually written as ''methods'' that belong to a ''class''
* In TypeScript most functions are actually written as ''methods'' that belong to a ''class''
Line 645: Line 645:
** Sensible auto-completion suggestions and type checking inside the function body
** Sensible auto-completion suggestions and type checking inside the function body


==== Functions Con't ====
==== Functions Con't ====


* Additional type annotation outside of the parentheses indicates the return type
* Additional type annotation outside of the parentheses indicates the return type
Line 655: Line 655:
* For functions it is worth leaving out the return type unless the function returns no value  
* For functions it is worth leaving out the return type unless the function returns no value  


==== Example 8 ====
==== Example 8 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
function countAvr(x: number, y: number, z: number): string {
function countAvr(x: number, y: number, z: number): string {
Line 666: Line 666:
</syntaxhighlight>
</syntaxhighlight>


==== Parameters ====
==== Parameters ====


* In JavaScript
* In JavaScript
Line 679: Line 679:
** We must check the value to see if it has been initialized (''typeof'' check)
** We must check the value to see if it has been initialized (''typeof'' check)


==== Example 9 ====
==== Example 9 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
function countAvr(x: number, y: number, z?: number): string {
function countAvr(x: number, y: number, z?: number): string {
Line 700: Line 700:
</syntaxhighlight>
</syntaxhighlight>


==== Parameters Con't ====
==== Parameters Con't ====


* '''Default parameter''' allows the argument to be omitted by calling code
* '''Default parameter''' allows the argument to be omitted by calling code
Line 708: Line 708:
** Keeps the TypeScript code listing short and succinct
** Keeps the TypeScript code listing short and succinct


==== Example 10 ====
==== Example 10 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
function conc(i: string[], sep = ',', b = 0, e = i.length) {
function conc(i: string[], sep = ',', b = 0, e = i.length) {
Line 731: Line 731:
</syntaxhighlight>
</syntaxhighlight>


==== Parameters Con't 1 ====
==== Parameters Con't 1 ====


* '''Rest parameter''' allows calling code to specify zero or more arguments of the specified type
* '''Rest parameter''' allows calling code to specify zero or more arguments of the specified type
Line 741: Line 741:
** ensure that the type annotation is an array type
** ensure that the type annotation is an array type


==== Example 11 ====
==== Example 11 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
function countAvr(...avr: number[]): string {
function countAvr(...avr: number[]): string {
Line 759: Line 759:
</syntaxhighlight>
</syntaxhighlight>


==== Overloads ====
==== Overloads ====


* Separate, well-named functions that make their different intentions explicit
* Separate, well-named functions that make their different intentions explicit
Line 772: Line 772:
*** optional, default, or rest parameters
*** optional, default, or rest parameters


==== Overloads Con't ====
==== Overloads Con't ====


* When we call a function that has overloads defined
* When we call a function that has overloads defined
Line 782: Line 782:
* Overloads allow a single function to be used in multiple cases
* Overloads allow a single function to be used in multiple cases


==== Example 12 ====
==== Example 12 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
function countAvr(x: string, y: string, z: string): string;
function countAvr(x: string, y: string, z: string): string;
Line 796: Line 796:
</syntaxhighlight>
</syntaxhighlight>


==== Specialized Overload Signatures ====
==== Specialized Overload Signatures ====


* '''Specialized overload signatures'''
* '''Specialized overload signatures'''
Line 808: Line 808:
*** We get back an appropriately typed NodeList depending on the HTML tag name we pass to the function
*** We get back an appropriately typed NodeList depending on the HTML tag name we pass to the function


==== Specialized Overload Signatures Con't ====
==== Specialized Overload Signatures Con't ====


* Rules
* Rules
Line 815: Line 815:
** The implementation signature must be compatible with all signatures
** The implementation signature must be compatible with all signatures


==== Example 13 ====
==== Example 13 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
class HandlerFactory {
class HandlerFactory {
Line 836: Line 836:
</syntaxhighlight>
</syntaxhighlight>


==== Arrow Functions ====
==== Arrow Functions ====
* Shorthand syntax for defining a function
* Shorthand syntax for defining a function
** Allow to leave out the ''function'' and ''return'' keywords
** Allow to leave out the ''function'' and ''return'' keywords
Line 846: Line 846:
*** This pattern is useful if we ever need both the original meaning of ''this'' as well as the functionally scoped meaning of ''this'' (events, etc)
*** This pattern is useful if we ever need both the original meaning of ''this'' as well as the functionally scoped meaning of ''this'' (events, etc)


==== Example 14 ====
==== Example 14 ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
// Arrow functions
// Arrow functions
Line 890: Line 890:
</syntaxhighlight>
</syntaxhighlight>


== Working with Classes and Interfaces ==
== Working with Classes and Interfaces ==


=== Interfaces ===
=== Interfaces ===


* Can be used for several purposes
* Can be used for several purposes
Line 905: Line 905:
** They are included to help us describe external code with structures that may not be analogous to classes
** They are included to help us describe external code with structures that may not be analogous to classes


==== Example 15 ====
==== Example 15 ====


<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
Line 933: Line 933:
</syntaxhighlight>
</syntaxhighlight>


==== Exercise 15 ====
==== Exercise 15 ====
<pre>
<pre>
Create a set of interfaces to describe a vehicle, passengers, location, and destination.
Create a set of interfaces to describe a vehicle, passengers, location, and destination.
Line 964: Line 964:
-->
-->


=== Interfaces Con't ===
=== Interfaces Con't ===


* They do not result in any compiled JavaScript code (due to type erasure)
* They do not result in any compiled JavaScript code (due to type erasure)
Line 977: Line 977:
** Very good to extend built-in definitions or external code
** Very good to extend built-in definitions or external code


==== Example 16 ====
==== Example 16 ====


<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
Line 1,009: Line 1,009:
</syntaxhighlight>
</syntaxhighlight>


=== Interfaces Con't 1 ===
=== Interfaces Con't 1 ===


* Can be used to describe
* Can be used to describe
Line 1,021: Line 1,021:
** Useful when used in conjunction with generics (covered later here)
** Useful when used in conjunction with generics (covered later here)


=== Classes ===
=== Classes ===


* The fundamental structural elements
* The fundamental structural elements
* Serve to organize our program
* Serve to organize our program


==== Constructors ====
==== Constructors ====


* All classes in TS have a constructor, whether we specify one or not
* All classes in TS have a constructor, whether we specify one or not
Line 1,036: Line 1,036:
*** And will pass arguments to the superclass (before initializing any of its own properties)
*** And will pass arguments to the superclass (before initializing any of its own properties)


==== Example 17 ====
==== Example 17 ====


<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
Line 1,088: Line 1,088:
</syntaxhighlight>
</syntaxhighlight>


==== Exercise 17 ====
==== Exercise 17 ====


<pre>
<pre>
Line 1,136: Line 1,136:
-->
-->


==== Access Modifiers ====
==== Access Modifiers ====


* Can be used to change the visibility of properties and methods within a class
* Can be used to change the visibility of properties and methods within a class
Line 1,152: Line 1,152:
* ''readonly'' keyword
* ''readonly'' keyword


==== Properties and Methods ====
==== Properties and Methods ====


* '''Instance properties''' are typically declared before the constructor in a TypeScript class
* '''Instance properties''' are typically declared before the constructor in a TypeScript class
Line 1,164: Line 1,164:
** Static properties are accessed using the class name
** Static properties are accessed using the class name


==== Methods ====
==== Methods ====


* Methods are defined like functions, but without the ''function'' keyword
* Methods are defined like functions, but without the ''function'' keyword
Line 1,176: Line 1,176:
** Static members have no access to nonstatic properties or methods
** Static members have no access to nonstatic properties or methods


==== Example 18 ====
==== Example 18 ====


<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
Line 1,209: Line 1,209:
</syntaxhighlight>
</syntaxhighlight>


==== Exercise 18 ====
==== Exercise 18 ====


<pre>
<pre>
Line 1,250: Line 1,250:
-->
-->


==== Property getters and setters ====
==== Property getters and setters ====


* TS supports property getters and setters, as long as we are targeting ECMAScript 5 or above
* TS supports property getters and setters, as long as we are targeting ECMAScript 5 or above
Line 1,258: Line 1,258:
** While preserving the appearance of a simple property to the calling code
** While preserving the appearance of a simple property to the calling code


==== Example 19 ====
==== Example 19 ====


<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
Line 1,289: Line 1,289:
</syntaxhighlight>
</syntaxhighlight>


==== Exercise 19 ====
==== Exercise 19 ====


<pre>
<pre>
Line 1,325: Line 1,325:
-->
-->


==== Heritage ====
==== Heritage ====


* A class can implement an interface using the ''implements'' keyword
* A class can implement an interface using the ''implements'' keyword
Line 1,335: Line 1,335:
-->
-->


==== Example 20 ====
==== Example 20 ====


<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
Line 1,383: Line 1,383:
</syntaxhighlight>
</syntaxhighlight>
<!-- TODO: make good exercise here, different then music stuff -->
<!-- TODO: make good exercise here, different then music stuff -->
=== Exercise 20 ===
=== Exercise 20 ===
<pre>
<pre>
Choose one of your business processes and map it into 2-3 classes  
Choose one of your business processes and map it into 2-3 classes  
Line 1,391: Line 1,391:
</pre>
</pre>


== Organizing your code with Namespaces ==
== Organizing your code with Namespaces ==


* Namespaces (previously ''Internal modules'')
* Namespaces (previously ''Internal modules'')
Line 1,402: Line 1,402:
** It can be hard to identify component dependencies, especially in a large application
** It can be hard to identify component dependencies, especially in a large application


=== Example 21 ===
=== Example 21 ===
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
namespace Shipping {
namespace Shipping {
Line 1,433: Line 1,433:
</syntaxhighlight>
</syntaxhighlight>


=== Exercise 21 ===
=== Exercise 21 ===
<pre>
<pre>
1. Discuss if it would make sense to rewrite solutions from ex17 and ex18 as namespace
1. Discuss if it would make sense to rewrite solutions from ex17 and ex18 as namespace
Line 1,517: Line 1,517:
-->
-->


=== Exercise 22 ===
=== Exercise 22 ===


<pre>
<pre>
Line 1,527: Line 1,527:
</pre>
</pre>


== Reusing code through Modules ==
== Reusing code through Modules ==


* Modules  
* Modules  
Line 1,545: Line 1,545:
** No longer needed - npm packages descriptions have it now
** No longer needed - npm packages descriptions have it now


=== Example 23 ===
=== Example 23 ===
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
// File 'greet.ts'
// File 'greet.ts'
Line 1,569: Line 1,569:
</syntaxhighlight>
</syntaxhighlight>


=== Exercise 23 ===
=== Exercise 23 ===


<pre>
<pre>
Line 1,628: Line 1,628:
-->
-->


== Generics ==
== Generics ==


Type variable, special kind of variable
Type variable, special kind of variable
Line 1,634: Line 1,634:
* allows to create reusable components
* allows to create reusable components


=== Example 24 ===
=== Example 24 ===
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
function whoAmI<G>(param: G): G {
function whoAmI<G>(param: G): G {
Line 1,646: Line 1,646:
</syntaxhighlight>
</syntaxhighlight>


=== Exercise 24 ===
=== Exercise 24 ===
* Test it with ''number, array, object''
* Test it with ''number, array, object''


=== Example 25 ===
=== Example 25 ===


Call signature of an object literal type
Call signature of an object literal type
Line 1,692: Line 1,692:
</syntaxhighlight>
</syntaxhighlight>


=== Exercise 25 ===
=== Exercise 25 ===
* Reuse class from ''Example 25'' with array type
* Reuse class from ''Example 25'' with array type
* Create your custom generic class, use function from ''Example 8''
* Create your custom generic class, use function from ''Example 8''
Line 1,750: Line 1,750:
-->
-->


== Compiling, testing and running TypeScript ==
== Compiling, testing and running TypeScript ==


* Compiling  
* Compiling  
Line 1,768: Line 1,768:
-->
-->


== Debugging TypeScript ==
== Debugging TypeScript ==


* Browser debuggers (Chrome inspector, Firebug, additional extensions, etc)
* Browser debuggers (Chrome inspector, Firebug, additional extensions, etc)
Line 1,775: Line 1,775:
** <small>https://code.visualstudio.com/docs/editor/debugging</small>
** <small>https://code.visualstudio.com/docs/editor/debugging</small>


== Launching your application ==
== Launching your application ==


* At the beginning usually it's a good idea to use "seed" (start-up) projects
* At the beginning usually it's a good idea to use "seed" (start-up) projects
Line 1,792: Line 1,792:
</pre>
</pre>


== Closing remarks ==
== Closing remarks ==


* All JavaScript is technically '''valid''' TypeScript
* All JavaScript is technically '''valid''' TypeScript

Revision as of 13:38, 17 June 2024


title
Typescript Training Course
author
Lukasz Sokolowski


Typescript

Typescript Training Materials

Introduction

  • Created by Microsoft
  • Released under an open-source Apache 2.0 License (2004)
  • Focused on making the development of JavaScript programs scale to many thousands of lines of code
  • The large-scale JavaScript programming problem by offering:
    • Better design-time tooling
    • Compile-time checking
    • Dynamic module loading at runtime

Intro con't

  • Typed superset of JavaScript
  • Is compiled to plain JavaScript
    • Programs written in TypeScript are highly portable
    • They can run on:
      • Almost any machine - in web browsers
      • Web servers
      • And even in native applications on operating systems that expose a JavaScript API (WinJS, Web APIs)

Intro con't 1

  • TypeScript language feature sources
    • ECMAScript 5 specification forms the basis of TypeScript and supplies the largest number of features in the language
    • The ECMAScript 6 specification adds modules for code organization and class-based object orientation
    • Additional Features - includes items that are not planned to become part of the ECMAScript standard (generics and type annotations, etc)
  • All of the TypeScript features can be converted into valid ECMAScript 5

Intro con't 2

  • Can consume the existing libraries and frameworks written in JavaScript
    • Angular, Backbone, Bootstrap, Durandal, jQuery, Knockout, Modernizr, PhoneGap, Prototype, Raphael, Underscore, React and many more
  • Once TypeScript program has been compiled it can be consumed from any JavaScript code
  • Similarity to JavaScript aids the debugging process
    • The generated JavaScript correlates closely to the original TypeScript code

Intro con't 3

  • Supported within:
    • Visual Studio, Eclipse
    • WebStorm, Sublime Text
    • Vi, IntelliJ, Emacs
    • Lots of other popular code editors

Installing TypeScript

  • Command line
    • Install with nodejs
      npm install -g typescript
      
    • Compile
      tsc yourProgram.ts
      
  • Plugin to: Visual Studio Code, Sublime Text, Eclipse, Vim, etc

Preparing a TypeScript project

Understanding Typing, Variables, and Functions

  • All of the JavaScript standard control structures are immediately available within a TypeScript program:
    • Control flows
    • Data types
    • Operators
    • Subroutines

Transferring JavaScript into TypeScript

  • All JavaScript is valid TypeScript
  • Existing JavaScript code added to a TypeScript file - all of the statements will be valid
    • There is a small number of exceptions
      • The with statement
      • Vendor specific extensions, such as Mozilla’s const keyword
  • Difference between valid code and error-free code in TypeScript
    • Although the code may work, the TypeScript compiler will warn about any potential problems it has detected

Example 1

// Not using with
var r = 6;
var a = Math.PI * r * r;

// Using with
var r = 6;
with (Math) {
  var a = PI * r * r;
}

r = 'some string';
// Static type checking will shout: "Cannot convert 'string' to 'number'".

Variables

  • Must follow the JavaScript naming rules
    • First character of variable name must be one of the following:
      • an uppercase letter, a lowercase letter, an underscore, a dollar sign
      • a Unicode character - Uppercase letter (Lu), Lowercase letter (Ll), Title case letter (Lt), Modifier letter (Lm), Other letter (Lo), or Letter number (Nl)
    • Subsequent characters follow the same rule but also allow:
      • numeric digits
      • a Unicode character — Non-spacing mark (Mn), Spacing combining mark (Mc), Decimal digit number (Nd), or Connector punctuation (Pc)
      • the Unicode characters U+200C (Zero Width Non-Joiner) and U+200D (Zero Width Joiner)
  • Simple tester https://mothereff.in/js-variables

Variables con't

  • Variables are functionally scoped
    • Once declared at the top level of program, they are available in the global scope
  • We should minimize the number of variables in the global scope to reduce naming collisions
  • Variables declared in functions, modules, or classes are available in the context they are declared
    • also in its nested contexts

Variables con't 1

  • To create a global variable, declare it without the var keyword
    • Often done inadvertently when the var is accidentally missed
    • It is rarely done deliberately
  • In a TypeScript program it will cause an error
    • which prevents a whole category of hard to diagnose bugs in our code

Variables con't 2

  • let vs old var
    • with var
      for (var i = 0; i < 10; i++) {
          setTimeout(function() { console.log(i); }, 100 * i);
      }
      
    • fixed in the old way
      for (var i = 0; i < 10; i++) {
          // capture the current state of 'i'
          // by invoking a function with its current value
          (function(i) {
              setTimeout(function() { console.log(i); }, 100 * i);
          })(i);
      }
      
    • fixed with let
      for (let i = 0; i < 10 ; i++) {
          setTimeout(function() { console.log(i); }, 100 * i);
      }
      

Variables con't 3

  • const declaration
    const maxTrainingsPerCart = 10;
    
    • Value cannot be changed once it is bound
    • Same scoping rules as let, but we can’t re-assign to them
    • Internal state of a const variable is still modifiable
      const trainingCartRestrictions = {
          name: "DefaultCart",
          maxTrainingsPerCart: 10
      }
      
      // Error
      trainingCartRestrictions = {
          name: "MyCart",
          maxTrainingsPerCart: 10
      };
      
      // Still works
      trainingCartRestrictions.name = "ConsultancyCart";
      trainingCartRestrictions.maxTrainingsPerCart--;
      
Const for objects, fixes
  • Object.freeze()
    const trainingCartRestrictions = Object.freeze({
        name: "DefaultCart",
        maxTrainingsPerCart: 10
    });
    
  • as const
    const trainingCartRestrictions = {
        name: "DefaultCart",
        maxTrainingsPerCart: 10
    } as const;
    

Example 2

function subtrNrs(c, d) {
  // missing 'var' keyword
  subtr = c - d;
  return subtr;
}

// An implicit global variable 'subtr', TypeScript will generate a "Could not find symbol" error
// To correct it: add the var keyword (makes variable locally scoped to 'subtrNrs'), or explicitly declare a variable in the global scope

Types

  • TypeScript is optionally statically typed
    • Types are checked automatically to prevent accidental assignments of invalid values
    • It is possible to opt out of this by declaring dynamic variables
    • Static type checking reduces errors caused by accidental misuse of types
    • We can create types to replace primitive types to prevent parameter ordering errors
    • Static typing allows development tools to provide intelligent auto-completion

Annotations

  • TypeScript can infer types automatically
    • the type of the variable is inferred from the value assigned
  • Type annotation specifies the type
    • Sometimes it isn’t able to determine the type
    • We want to make a type explicit either for safety or readability
    • For variable, the type annotation comes after the identifier and is preceded by a colon

Annotations Con't

The type used to specify an annotation can be:

  • A primitive type, an array type, a function signature
  • Any complex structure we want to represent
    • Including the names of classes and interfaces
  • To mark a variable’s type as dynamic, we can use the special any type
    • No checks are made on dynamic types

Example 3

// primitive type annotation
var secondName: string = 'Robert';
var footLength: number = 26.50;
var isMarried: boolean = true;

// array type annotation
var languages: string[] = ['JavaScript', 'TypeScript', 'jQuery'];

// function annotation with parameter type annotation and return type annotation
var shoutHi: (name: string) => string;

// implementation of 'shoutHi' function
shoutHi = function (name: string) {
  return 'Hi ' + name;
};

// object type annotation
var human: { secondName: string; footLength: number; };

// Implementation of a person object
human = {
  secondName: 'Mat',
  footLength: 28
};

Primitive Types

  • Directly represent the underlying JavaScript types and follow the standards set for those types
    • String - UTF-16 code units
    • Boolean - true or false literals
    • Number - double-precision 64-bit floating point value
  • No special types to represent integers or other specific variations on a number
  • any is exclusive to TypeScript and denotes a dynamic type
    • used whenever TypeScript is unable to infer a type, or when we explicitly want to make a type dynamic
    • equivalent to opting out of type checking for the life of the variable

Primitive Types Con't

Types that refer to the absence of values:

  • undefined - value of a variable that has not been assigned a value
  • null - represents an intentional absence of an object value
    • method that searched an array of objects to find a match, it could return null to indicate that no match was found
  • void - represents functions that do not return a value or as a type argument for a generic class or function
  • never - no return, not even void ( ex. error, infinite loop, exception thrown )

Arrays

  • Have precise typing for their contents
    • We add square brackets after the type name
    • Works for all types whether they are primitive or custom
    • When we add an item to the array its type will be checked to ensure it is compatible
    • When we access elements in the array, we will get quality auto-completion because the type of each item is known

Example 4

interface Movie {
  title: string;
  lengthMinutes: number;
}

// The array is typed using the Movie interface
var movies: Movie[] = [];

// Each item added to the array is checked for type compatibility
movies.push({
  title: 'American History X',
  lengthMinutes: 119,
  production: 'USA'    // example of structural typing
});

movies.push({
  title: 'Sherlock Holmes',
  lengthMinutes: 128,
});

movies.push({
  title: 'Scent of a Woman',
  lengthMinutes: 157
});

function compareMovieLengths(x: Movie, y: Movie) {
  if (x.lengthMinutes > y.lengthMinutes) {
    return -1;
  }
  if (x.lengthMinutes < y.lengthMinutes) {
    return 1;
  }
  return 0;
}

// The array.sort method expects a comparer that accepts 2 Movies
var moviesOrderedLength = movies.sort(compareMovieLengths);

// Get the first element from the array, which is the longest
var longestMovie = moviesOrderedLength[0];

console.log(longestMovie.title); // Scent of a Woman

Exercise 4

Describe some Monuments with:
- interface
- array
Compare their heights in a function, find the tallest one.


Enumerations

  • Represent a collection of named elements
    • To avoid littering our program with hard-coded values
    • By default zero based
    • We can specify the first value, so numbers will increment from the specified value
    • We can also specify values for all identifiers, if needed
    • The value passed when an identifier name is specified is the number that represents the identifier
    • To get the identifier name from the enumeration, treat the enumeration like an array

Enumerations Con't

In TypeScript enumerations are open ended

  • All declarations with the same name inside a common root will contribute toward a single type
  • We can define an enumeration across multiple blocks
    • Subsequent blocks after the first declaration must specify the numeric value to be used to continue the sequence
    • Useful technique for extending code from third parties, in ambient declarations and from the standard library

Example 5

enum MusicKind {
  Classic,
  Rap,
  Pop,
  Rock,
  Dance,
  Funk
}

var kind = MusicKind.Funk;    // 5

var kindName = MusicKind[kind];    // 'Funk'


// Enumeration split across multiple blocks
enum FootSize {
  Small,
  Medium
}

// ...

enum FootSize {
  Large = 2,
  XL,
  XXL
}

Exercise 5

5.1. Describe types of Vehicles via enumeration.

5.2. Use enumeration to describe sizes of boxes (for example if we sell something in them):
- split it across multiple blocks.


Assertions

Can override the type

  • TypeScript determines that an assignment is invalid, but we know it's a special case
    • We are guaranteeing that the assignment is valid
  • The type assertion precedes a statement
  • It overrides the type as far as the compiler is concerned
    • There are still checks performed when we assert a type
    • We can force a type assertion by adding an additional <any>

Example 6

interface Musician {
  singles: number;
  albums: number;
}

interface Rapper {
  singles: number;
  albums: number;
  styles: number;
}

var eminem: Musician = {
  singles: 120,
  albums: 80,
  styles: 4
}

// Errors: Cannot convert Musician to Rapper
var rapper: Rapper = eminem;

// Works
var rapper: Rapper = <Rapper>eminem;


// Forced type assertions
var rapperName: string = 'Rapper Eminem';

// Error: Cannot convert 'string' to 'number'
var singles: number = <number> rapperName;

// Works
var singles: number = <number> <any> rapperName;

Exercise 6

Prepare two interfaces: House and Mansion.
The second should have one more property than the first one.
Declare new variable with type from House interface
- but provide also that additional parameter(property) from the Mansion interface
- fix it with type assertion
Finally try to force the type assertion.


Operators

Some JavaScript operators have special significance within TypeScript

  • because of type restrictions
  • they affect types
Increment, Decrement
  • Increment (++) and decrement (--) operators can only be applied to variables of type
    • any, number, or enum
  • The operator usually works on variables with the any type, as no type checking is performed on these variables
  • When incrementing or decrementing an enumeration, the number representation is updated
    • Incrementing results in the next element in the enumeration
    • Decrementing results in the previous element in the enumeration
    • We can increase and decrease the value beyond the bounds of the enumeration
Example 7
enum FootSize {
  Small,
  Medium,
  Large,
  XL,
  XXL
}

var fsize = FootSize.Small;
++fsize;
console.log(FootSize[fsize]); // Medium

var fsize = FootSize.XL;
--fsize;
console.log(FootSize[fsize]); // Large

var fsize = FootSize.XXL;
++fsize;
console.log(FootSize[fsize]); // undefined
Binary Operators
  • Binary operators: - * / % << >> >>> & ^ |
    • Designed to work with two numbers
    • In TypeScript, it is valid to use the operators with variables of type number or any
    • Where we are using a variable with the any type, we should ensure it contains a number
    • The result of an operation in this list is always a number
Binary Operators Con't
  • The plus (+) operator can be
    • Mathematical addition operator
    • Concatenation operator (glue strings)
  • This will be caught in a TypeScript program if we
    • try to assign a string to a variable of the number type
    • try to return a string for a function that is annotated to return a number
Logical Operators
  • NOT - ! inverts, !! converts to BOOLEAN
  • AND - &&
  • OR - ||
  • Short-Circuit Evaluation
  • Conditional Operator - isOK ? 'Y' : 'N'
Type Operators
  • Can assist us when working with objects in JavaScript
  • Relevant to working with classes - typeof, instanceof, in, delete

Functions

  • In TypeScript most functions are actually written as methods that belong to a class
  • Functions are improved by a number of TypeScript language features
  • With functions there are a number of places that can be annotated with type information
  • Each parameter can have a different type
    • When the function is called, the type of each argument passed to the function is checked
  • The types are also known within the function
    • Sensible auto-completion suggestions and type checking inside the function body

Functions Con't

  • Additional type annotation outside of the parentheses indicates the return type
  • We can use the void type to indicate that the function does not return a value
    • Prevent code inside the function from returning a value
    • Stop calling code from assigning the result of the function to a variable
  • It is possible to specify all of the types used in a function explicitly
    • We should rather rely on type inference
  • For functions it is worth leaving out the return type unless the function returns no value

Example 8

function countAvr(x: number, y: number, z: number): string {
	var together = x + y + z;
	var avr = together / 3;
	return 'The average is ' + avr;
}

var res = countAvr(3, 2, 10); // 'The average is 5'

Parameters

  • In JavaScript
    • we can call a function without any arguments (even if specified in it's declaration)
    • we can pass more arguments than the function requires
  • In TypeScript the compiler checks each call
    • Warns if the arguments fail to match the required parameters in number or type
  • Thoroughly checked, we need to annotate optional parameters
    • Inform the compiler that it is acceptable for an argument to be omitted by calling code
    • To make a parameter optional, suffix the identifier with a question mark
    • Optional parameters must be located after any required parameters
    • We must check the value to see if it has been initialized (typeof check)

Example 9

function countAvr(x: number, y: number, z?: number): string {
	var tog = x;
	var counter = 1;
	
	tog += y;
	counter++;
	
	if (typeof z !== 'undefined') {
		tog += z;
		counter++;
	}
	
	var avr = tog / counter;
	return 'The average is ' + avr;
}

var res = countAvr(2, 8); // 'The average is 5'

Parameters Con't

  • Default parameter allows the argument to be omitted by calling code
  • In cases where the argument is not passed the default value will be used instead
  • To supply a default value for a parameter, assign a value in the function declaration
  • Checks only appear in the output
    • Keeps the TypeScript code listing short and succinct

Example 10

function conc(i: string[], sep = ',', b = 0, e = i.length) {
	var resu = '';
	
	for (var k = b; k < e; k++) {
		resu += i[k];
		if (k < (e - 1)) {
			resu += sep;
		}
	}
	return resu;
}

var items = ['D', 'E', 'F'];

// 'D,E,F'
var res = conc(items);

// 'E-F'
var partRes = conc(items, '-', 1);

Parameters Con't 1

  • Rest parameter allows calling code to specify zero or more arguments of the specified type
  • Must follow these rules
    • Only one rest parameter is allowed
    • Must appear last in the parameter list
    • Must be an array type
  • To declare a rest parameter, prefix the identifier with three periods
    • ensure that the type annotation is an array type

Example 11

function countAvr(...avr: number[]): string {
	var t = 0;
	var c = 0;

	for (var k = 0; k < avr.length; k++) {
		t += avr[k];
		c++;
	}

	var av = t / c;
	return 'The average is ' + av;
}

var res = countAvr(1, 6, 8, 9, 11); // 'The average is 7'

Overloads

  • Separate, well-named functions that make their different intentions explicit
  • In TypeScript all decorate a single implementation
  • The actual signature of the function appears last and is hidden by the overloads
    • This final signature is called an implementation signature
      • Must define parameters and a return value, that are compatible with all preceding signatures
      • Return types for each overload can be different
      • Parameter lists can differ in types and in number of arguments
  • If an overload specifies fewer parameters than the implementation signature
    • the implementation signature would have to make the extra parameters
      • optional, default, or rest parameters

Overloads Con't

  • When we call a function that has overloads defined
    • the compiler constructs a list of signatures
    • attempts to determine the signature that matches the function call
  • If there are no matching signatures the call results in an error
  • If one or more signature matches, the earliest of the matching signatures determines the return type
    • In the order they appear in the file
  • Overloads allow a single function to be used in multiple cases

Example 12

function countAvr(x: string, y: string, z: string): string;
function countAvr(x: number, y: number, z: number): string;
// implementation signature
function countAvr(x: any, y: any, z: any): string {
	var t = parseInt(x, 10) + parseInt(y, 10) + parseInt(z, 10);
	var av = t / 3;
	return 'The average is ' + av;
}

var res = countAvr(2, 4, 9); // 5

Specialized Overload Signatures

  • Specialized overload signatures
    • The ability in TypeScript to create overloads based on string constants
    • The overloads are based on the string value of an argument
    • A single implementation of a function can be re-used
      • In many cases without requiring the calling code to convert the types
  • The nonspecialized signature returns a superclass
    • With each overload returning a more specialized subclass that inherits the superclass
    • An example: (DOM) method getElementsByTagName
      • We get back an appropriately typed NodeList depending on the HTML tag name we pass to the function

Specialized Overload Signatures Con't

  • Rules
    • There must be at least one nonspecialized signature
    • Each specialized signature must return a subtype of a nonspecialized signature
    • The implementation signature must be compatible with all signatures

Example 13

class HandlerFactory {
	getHandler(type: 'Random'): RandomHandler;
	getHandler(type: 'Reversed'): ReversedHandler;
	getHandler(type: string): Handler; // non-specialized signature
	
	getHandler(type: string): Handler { // implementation signature

		switch (type) {
			case 'Random':
				return new RandomHandler();
			case 'Reversed':
				return new ReversedHandler();
			default:
				return new Handler();
		}
	}
}

Arrow Functions

  • Shorthand syntax for defining a function
    • Allow to leave out the function and return keywords
    • We can also use it to preserve the lexical scope of the this keyword
      • Useful when working with callbacks or events (when it's easy to lose the current scope)
      • Behind the scenes - just before the arrow function is defined - TS creates _this and sets its value to the current value of this
      • It also substitutes any usages of this within the function with _this, so the statement now reads _this.property in the JavaScript output
      • The use of the _this variable inside the function creates a closure around the variable, which preserves its context along with the function
      • This pattern is useful if we ever need both the original meaning of this as well as the functionally scoped meaning of this (events, etc)

Example 14

// Arrow functions
var addNrs = (x: number, y: number) => x + y;

var addNrs = (x: number, y: number) => {
	return x + y;
}

var addNrs = function (x: number, y: number) {
	return x + y;
}

// Wrapping an object in parentheses
var createName = (f: string, l: string) => ({first: f, last: l});

// Preserving scope with arrow syntax
var ScopeLosingEx = {
	text: "Property from lexical scope",
	run: function () {
	// Here we have the usual JS way
		setTimeout( function() {
			alert(this.text);
		}, 1000);
	}
};

// alerts undefined
ScopeLosingEx.run();

var ScopePreservingEx = {
	text: "Property from lexical scope",
	run: function () {
	// Here below goes the main change in code
		setTimeout( () => {
			alert(this.text);
		}, 1000);
	}
};

// alerts "Property from lexical scope"
ScopePreservingEx.run();

Working with Classes and Interfaces

Interfaces

  • Can be used for several purposes
    • As an abstract type that can be implemented by concrete classes
    • To define any structure in our TypeScript program
  • The building blocks for defining operations
    • That are available in third-party libraries and frameworks that are not written in TypeScript
  • Declared with the interface keyword
  • Contain a series of annotations to describe the contract represented by them
    • Can describe properties, functions, constructors and indexers
  • To describe our own classes, we won’t need to define constructors or indexers
    • They are included to help us describe external code with structures that may not be analogous to classes

Example 15

// Interfaces examples

interface CourseVenue {
	// Properties
	city: string;
	country: string;
}

interface CourseParticipant {
	// Properties
	name: string;
}

interface CourseEvent {
	// Constructor
	new() : CourseEvent;
	// Properties
	currentLocation: CourseVenue;
	// Methods
	bookVenue(venue: CourseVenue);
	addDelegate(delegate: CourseParticipant);
	removeDelegate(delegate: CourseParticipant);
}

Exercise 15

Create a set of interfaces to describe a vehicle, passengers, location, and destination.
Declare properties and methods using type annotations.
Declare constructors using the ''new'' keyword.


Interfaces Con't

  • They do not result in any compiled JavaScript code (due to type erasure)
    • Used at design time to provide autocompletion
    • Used at compile time to provide type checking
  • Open like enumerations - all declarations with a common root are merged into a single interface
    • This means we must ensure that the combined interface is valid
    • We can’t declare the same property in multiple blocks of the same interface ("duplicate identifier" error)
    • We can’t define the same method (although we can add overloads to an existing one)
  • Declaring an interface in several blocks
    • Not a particularly valuable feature for own program
    • Very good to extend built-in definitions or external code

Example 16

// Built-in NodeList interface
/*
interface NodeList {
	length: number;
	item(index: number): Node;
	[index: number]: Node;
}
*/

// An additional interface block extends the built-in NodeList interface 
// to add an onclick property that is not available natively.
// The implementation isn’t included in this example - it may be a new web standard 
// or a JavaScript library that adds the additional functionality. 
// As far as the compiler is concerned, the interface that is defined in the standard library 
// and the interface that is defined in our TypeScript file are one interface

// Extending the NodeList interface example
interface NodeList {
	// Function arrow shortcut (event case)
	onclick: (event: MouseEvent) => any;
}

var nodeList = document.getElementsByTagName('div');

nodeList.onclick = function (event: MouseEvent) {
	alert('Clicked');
};

Interfaces Con't 1

  • Can be used to describe
    • A contract we intend to implement in a class
    • Any structure we can conceive in our program (functions, variables, objects, or combinations of them)
    • When a method accepts an options object as a parameter (jQuery, other similar frameworks)
      • An interface can be used to provide autocompletion for the complex object argument
  • Can inherit from a class in the same way a subclass can inherit from a superclass
    • The interface inherits all of the members of the class, but without any implementation
    • Anything added to the class will also be added to the interface
    • Useful when used in conjunction with generics (covered later here)

Classes

  • The fundamental structural elements
  • Serve to organize our program

Constructors

  • All classes in TS have a constructor, whether we specify one or not
    • If we leave out the constructor, the compiler will automatically add one
    • Class that doesn’t inherit from another class
      • The automatic constructor will be parameterless and will initialize any class properties
    • Class extends another class
      • The automatic constructor will match the superclass signature
      • And will pass arguments to the superclass (before initializing any of its own properties)

Example 17

// Constructors example
class Training {
	constructor(private category: string, private title: string, private noOfDays: number) {

	}

	buy() {
		console.log('Buying this ' + this.noOfDays + ' day(s) ' + this.title + ' course from category ' + this.category);
	}
}

// Constructor parameters are mapped to member variables.
// If we prefix a constructor parameter with an access modifier (ie. private),
// it will automatically be mapped for us.
// We can refer to these constructor parameters as if they were declared 
// as properties on the class, for example this.title, can be used anywhere within the Training class 
// to obtain the Training title on that instance

class BuyTraining {
	constructor(private trainings: Training[]) {

	}

	buy() {
		var training = this.chooseTraining();
		training.buy();
	}

	private chooseTraining() {
		// Decision can come for example from the form in the browser, another webservice, db, etc
		var whichTraining = 2;

		return this.trainings[whichTraining];
	}
}

var trainings = [
	new Training('Drupal', 'Drupal 8 for Developers', 2),
	new Training('Angular', 'Angular 2 Fundamentals', 3),
	new Training('Nodejs', 'Developing web applications with the MEAN stack', 5),
	new Training('SQL', 'T-SQL basics', 2),
	new Training('Management', 'BPMN for code architects', 3)
];

var choice = new BuyTraining(trainings);

choice.buy();

Exercise 17

Create structure about songs and make jukebox, which will randomly get the song from the list of songs.
  • Math.floor(Math.random() * songCount);

Access Modifiers

  • Can be used to change the visibility of properties and methods within a class
  • By default, properties and methods are public (no need to use public keyword)
  • If we want constructor parameters to be mapped to public properties automatically
    • They have to be prefixed with the public keyword
  • private keyword hides a property or method
    • This restricts the visibility to within the class only
    • The member won’t appear in auto-completion lists outside of the class
    • Any external access will result in a compiler error
    • A class member marked as private, can’t even be seen by subclasses
    • If we need to access a property or method from a subclass
      • We can made it public
      • We can use protected keyword
  • readonly keyword

Properties and Methods

  • Instance properties are typically declared before the constructor in a TypeScript class
  • A property definition: an optional access modifier, the identifier, and a type annotation
    • public name: string;
      
    • with a value:
      public name: string = 'Jane';
      
  • When our program is compiled, the property initializers are moved into the constructor
  • Instance properties can be accessed from within the class using the this keyword
  • If the property is public it can be accessed using the instance name
  • Static properties are defined with the static keyword between the access modifier and the identifier
    • Static properties are accessed using the class name

Methods

  • Methods are defined like functions, but without the function keyword
  • Can be annotated with parameters and return value type
  • Can be prefixed with an access modifier to control its visibility (public by default)
  • Can be accessed from within the class via this keyword
  • If public, can be accessed outside of the class using the instance name
  • Static members can be called even when no instance of the class has been created
    • Only a single instance of each static member exists in our program
    • All static members are accessed via the class name and not an instance name
    • Static members have no access to nonstatic properties or methods

Example 18

// Properties and methods
class CartWithTrainings {
	private trainings: Training[] = [];

	static maxTraining: number = 10;

	constructor(public cartId: string) {
	}

	addTraining(training: Training) {
		if (this.trainings.length >= CartWithTrainings.maxTraining) {
			throw new Error('To many courses in your Cart.');
		}
		this.trainings.push(training);
	}
}

// Creating a new instance
var coursesCart = new CartWithTrainings('Cart1');

// Accessing a public instance property
var nameCart = coursesCart.cartId;

// Calling a public instance method
coursesCart.addTraining(new Training('GIT', 'Git for Users', 1));

// Accessing a public static property
var maxTrainings = CartWithTrainings.maxTraining;

Exercise 18

Make a Playlist of songs (reuse code from exercise 17)
- declare class for playlist
-- use private and static properties
- prepare 'addSong' method
- create new instance, access and call: 
-- playlist, its public instance property, public instance method, public static property


Property getters and setters

  • TS supports property getters and setters, as long as we are targeting ECMAScript 5 or above
  • The syntax is identical to method signatures
    • Except they are prefixed by either the get or set keyword
  • Allow to wrap property access with a method
    • While preserving the appearance of a simple property to the calling code

Example 19

// Property getters and setters example
interface Invoice {
	id: string;
	clientId: number;
}

class FranchiseeAccountancyTool {
	private _invoice;

	constructor(public accToolKey: string, public taxRate: string) {
	}

	get invoice() {
		return this._invoice;
	}

	set invoice(inv: Invoice) {
		this._invoice = inv;
	}
}

var consultancyInv = { id: 'INV_20_12072015', clientId: 234 };

var accToolInstance = new FranchiseeAccountancyTool('cnaj837tjdhsu#jd9_fd8', '201');

accToolInstance.invoice = consultancyInv;

Exercise 19

Create an interface describing stock item
- allow to get and set it within warehouse location (make it as a class)
- make new slot in warehouse and put there new stock item object


Heritage

  • A class can implement an interface using the implements keyword
  • a class can inherit from another class using the extends keyword


Example 20

// Class heritage example
interface Audio {
  play(): any;
}

class Song implements Audio {
  constructor(private artist: string, private title: string) {
  }
  play(): void {
    console.log('Playing ' + this.title + ' by ' + this.artist);
  }
  static Comparer(a: Song, b: Song) {
    if (a.title === b.title) {
      return 0;
    }
    return a.title > b.title ? 1 : -1;
  }
}
class Playlist {
  constructor(public songs: Audio[]) {
  }
  play() {
    var song = this.songs.pop();
    song.play();
  }

  sort() {
    this.songs.sort(Song.Comparer);
  }
}
class RepeatingPlaylist extends Playlist {
  private songIndex = 0;
  constructor(songs: Song[]) {
    super(songs);
  }
  play() {
    this.songs[this.songIndex].play;
    this.songIndex++;
    if (this.songIndex >= this.songs.length) {
      this.songIndex = 0;
    }
  }
}

Exercise 20

Choose one of your business processes and map it into 2-3 classes 
- provide an interface
- at least one class should use provided interface
- make one class inherit from another

Organizing your code with Namespaces

  • Namespaces (previously Internal modules)
    • Named JavaScript objects in the global namespace
    • Simple construct to use
    • Can span multiple files
    • Can be concatenated (using --outFile).
    • Good way to structure our code in a Web Application
      • With all dependencies included as <script> tags in our HTML page
    • It can be hard to identify component dependencies, especially in a large application

Example 21

namespace Shipping {
    // Available as Shipping.Ship
    export interface Ship {
        name: string;
        port: string;
        displacement: number;
    }
    // Available as Shipping.Ferry
    export class Ferry implements Ship {
        constructor(
        public name: string,
        public port: string,
        public displacement: number) {
        }
    }
    // Only available inside of the Shipping module
    let defaultDisplacement = 4000;
    class PrivateShip implements Ship {
        constructor(
        public name: string,
        public port: string,
        public displacement: number = defaultDisplacement) {
        }
    }
}

let ferry = new Shipping.Ferry('Assurance', 'London', 3220);

Exercise 21

1. Discuss if it would make sense to rewrite solutions from ex17 and ex18 as namespace
- if yes, try to do it
2. Improve the code below with namespace
- add another validator for numbers(zip code) and related regexp pattern (/^[0-9]+$/)
- export validators
- hide regexps
interface StringValidator {
    isAcceptable(s: string): boolean;
}

let lettersRegexp = /^[A-Za-z]+$/;

class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) {
        return lettersRegexp.test(s);
    }
}

// Some samples to try
let strings = ["Hello", "98052", "101"];

// Validators to use
let validators: { [s: string]: StringValidator; } = {};
validators["Letters only"] = new LettersOnlyValidator();

// Show whether each string passed each validator
for (let s of strings) {
    for (let name in validators) {
        let isMatch = validators[name].isAcceptable(s);
        console.log(`'${ s }' ${ isMatch ? "matches" : "does not match" } '${ name }'.`);
    }
}


Exercise 22

Split previous code into a couple of files:
- val.ts, lettersVal.ts, zipVal.ts, test.ts
- provide necessary references in the 'test.ts'
-- for example "/// <reference path="val.ts" />"
- compile it as one output file (using --outFile)

Reusing code through Modules

  • Modules
    • Can contain both code and declarations
    • Declare their dependencies
    • Have a dependency on a module loader (for example CommonJs/Require.js).
    • Might not be optimal for a small JS application
    • For larger applications
      • Long term modularity and maintainability benefits
      • Better code reuse
      • Stronger isolation
        • Two different modules will never contribute names to the same scope
      • Better tooling support for bundling
    • Default and recommended approach for nodejs apps
  • Third party libraries, extensions, etc
    • No longer needed - npm packages descriptions have it now

Example 23

// File 'greet.ts'
function greet(name: string): void {
  console.log('Hello ' + name);
}
//// nodejs way
export = greet;
//// Example with an interface - modern js way
// export { nameOfTheInterface }

* =========================================== *

// File 'hello.ts'
//// Without 'ts' 
// var hello = require('./scripts/greet');
//// With 'ts'
import hello = require('./scripts/greet'); // with 'ts'
// Example with interface
// import { nameOfTheInterface } from "./scripts/greet" 

hello('Mark'); // instead of hello.greet('Mark');

Exercise 23

Rewrite code from ex22 into modules.
(hints:
- from the dependency: export { StringValidator }
- in the main file: import { StringValidator } from "./val"; 
)


Generics

Type variable, special kind of variable

  • works on types rather than values
  • allows to create reusable components

Example 24

function whoAmI<G>(param: G): G {
  return param;
}

let resu = whoAmI<string>("I am String");  // type of output will be 'string'

// type argument inference
let resu1 = whoAmI("I also am String");  // type of output will be 'string'

Exercise 24

  • Test it with number, array, object

Example 25

Call signature of an object literal type

function whoAmI<U>(param: U): U {
    return param;
}

let amIme: {<U>(arg: U): U} = whoAmI;

Generic interface

interface GenericWhoAmIFn {
    <B>(param: B): B;
}

function whoAmI<B>(param: B): B {
    return param;
}

let amIme: GenericWhoAmIFn = whoAmI;
console.log( amIme("Of course not, you're in the Matrix, Mate..") );

Generic class

class GenericInvoice<C> {
    invoiceOwner: C;
    send: (invID: C, invType: C) => C;
}

let myInvoice = new GenericInvoice<string>();
myInvoice.invoiceOwner = 'Judy';
myInvoice.send = 
  function(invID, invType) { 
    let invRemarks = invType + " invoice with number " + invID + " has been issued";
    return invRemarks;
  };

console.log( myInvoice.send("12-23012018", "ProForma") + " by " + myInvoice.invoiceOwner );

Exercise 25

  • Reuse class from Example 25 with array type
  • Create your custom generic class, use function from Example 8

Compiling, testing and running TypeScript

  • Compiling
    • Command line
       tsc -p <project_path>
       tsc file_name.ts
      
  • Testing
    • Possible in plain TypeScript code
    • Testing frameworks written in JavaScript
      • Jasmine
      • Mocha
      • QUnit

Debugging TypeScript

Launching your application

  • At the beginning usually it's a good idea to use "seed" (start-up) projects
    • Full and pre-configured environment, easy to extend and learn from it
    • Good examples of code - application and tests, ready to be reused
  • TS propositions

Exercise

Install one of these quick-starters
- https://github.com/Microsoft/TypeScript-React-Starter#typescript-react-starter
- https://angular.io/guide/quickstart
- https://github.com/Microsoft/TypeScript-Node-Starter#typescript-node-starter
Create simple TODO list with MVC (Model View Controller) approach. 

Closing remarks

  • All JavaScript is technically valid TypeScript
  • Primitive types are closely linked to JavaScript primitive types
  • Types are inferred in TypeScript, but you can supply annotations to make types explicit or deal with cases the compiler can’t handle
  • Interfaces can be used to describe complicated structures, to make type annotations shorter
  • All TypeScript arrays are generic
  • There are special cases where type coercion applies, but in most cases type checking will generate errors for invalid use of types
  • You can add optional, default, and rest parameters to functions and methods
  • Arrow functions provide a short syntax for declaring functions, but can also be used to preserve the lexical scope
  • Enumerations, interfaces, and modules are open, so multiple declarations that have the same name in the same common root will result in a single definition
  • Classes bring structure to your TypeScript program and make it possible to use common design patterns
  • Modules work as namespaces and external modules can help with module loading
  • You can obtain type information at runtime, but this should be used responsibly

  • What is coercion?
    • Type coercion means that when the operands of an operator are different types, one of them will be converted to an "equivalent" value of the other operand's type. For instance, if you do:
    • boolean == integer
    • the boolean operand will be converted to an integer: false becomes 0, true becomes 1. Then the two values are compared.