Sunteți pe pagina 1din 272

TableofContents

Introduction

Introduction
 

1.1

1.1

GettingStarted

GettingStarted
 

1.2

1.2
WhyTypeScript   1.2.1

WhyTypeScript

 

1.2.1

1.2.1

JavaScript

JavaScript
 

1.3

1.3
Awful   1.3.1

Awful

 

1.3.1

1.3.1
Closure   1.3.2

Closure

 

1.3.2

1.3.2

FutureJavaScriptNow

FutureJavaScriptNow
 

1.4

1.4
Classes   1.4.1

Classes

 

1.4.1

1.4.1
 
  ClassesEmit   1.4.1.1

ClassesEmit

 

1.4.1.1

1.4.1.1
ClassesSuper   1.4.1.2

ClassesSuper

 

1.4.1.2

1.4.1.2
ClassesExtensibility 1.4.1.3

ClassesExtensibility

1.4.1.3

1.4.1.3
ArrowFunctions   1.4.2

ArrowFunctions

 

1.4.2

1.4.2
RestParameters   1.4.3

RestParameters

 

1.4.3

1.4.3
let 1.4.4

let

1.4.4

1.4.4
const   1.4.5

const

 

1.4.5

1.4.5
Destructuring   1.4.6

Destructuring

 

1.4.6

1.4.6
for of   1.4.7

for of

 

1.4.7

1.4.7
Iterators   1.4.8

Iterators

 

1.4.8

1.4.8
TemplateStrings   1.4.9

TemplateStrings

 

1.4.9

1.4.9
SpreadOperator   1.4.10

SpreadOperator

 

1.4.10

1.4.10
Enums   1.4.11

Enums

 

1.4.11

1.4.11
Promise   1.4.12

Promise

 

1.4.12

1.4.12
Generators   1.4.13

Generators

 

1.4.13

1.4.13
AsyncAwait   1.4.14

AsyncAwait

 

1.4.14

1.4.14

Project

Project
 

1.5

1.5
CompilationContext   1.5.1

CompilationContext

 

1.5.1

1.5.1
 
  tsconfig.json   1.5.1.1

tsconfig.json

 

1.5.1.1

1.5.1.1
WhichFiles?   1.5.1.2

WhichFiles?

 

1.5.1.2

1.5.1.2
DeclarationSpaces   1.5.2

DeclarationSpaces

 

1.5.2

1.5.2
Modules   1.5.3

Modules

 

1.5.3

1.5.3
 
  FileModuleDetails 1.5.3.1

FileModuleDetails

1.5.3.1

1.5.3.1
globals.d.ts   1.5.3.2

globals.d.ts

 

1.5.3.2

1.5.3.2
Namespaces   1.5.4

Namespaces

 

1.5.4

1.5.4

NodeJSQuickStart

NodeJSQuickStart
 

1.6

1.6

BrowserQuickStart

BrowserQuickStart
 

1.7

1.7

TypeScript'sTypeSystem

TypeScript'sTypeSystem
 

1.8

1.8
JSMigrationGuide   1.8.1

JSMigrationGuide

 

1.8.1

1.8.1
@types   1.8.2

@types

 

1.8.2

1.8.2
AmbientDeclarations   1.8.3

AmbientDeclarations

 

1.8.3

1.8.3
DeclarationFiles   1.8.3.1

DeclarationFiles

 

1.8.3.1

1.8.3.1
Variables   1.8.3.2

Variables

 

1.8.3.2

1.8.3.2
Interfaces   1.8.4

Interfaces

 

1.8.4

1.8.4
lib.d.ts   1.8.5

lib.d.ts

 

1.8.5

1.8.5
Functions   1.8.6

Functions

 

1.8.6

1.8.6
TypeAssertion   1.8.7

TypeAssertion

 

1.8.7

1.8.7
Freshness   1.8.8

Freshness

 

1.8.8

1.8.8
TypeGuard   1.8.9

TypeGuard

 

1.8.9

1.8.9
StringLiteralType   1.8.10

StringLiteralType

 

1.8.10

1.8.10
Readonly   1.8.11

Readonly

 

1.8.11

1.8.11
TypeInference   1.8.12

TypeInference

 

1.8.12

1.8.12
TypeCompatibility   1.8.13

TypeCompatibility

 

1.8.13

1.8.13
NeverType   1.8.14

NeverType

 

1.8.14

1.8.14
DiscriminatedUnions   1.8.15

DiscriminatedUnions

 

1.8.15

1.8.15

JSX

JSX

1.9

1.9

Options

Options
 

1.10

1.10
noImplicitAny   1.10.1

noImplicitAny

 

1.10.1

1.10.1

TIPs

TIPs

1.11

1.11
QuickObjectReturn   1.11.1

QuickObjectReturn

 

1.11.1

1.11.1
StringBasedEnums   1.11.2

StringBasedEnums

 

1.11.2

1.11.2
NominalTyping   1.11.3

NominalTyping

 

1.11.3

1.11.3
StatefulFunctions   1.11.4

StatefulFunctions

 

1.11.4

1.11.4
BindisBad   1.11.5

BindisBad

 

1.11.5

1.11.5
Currying   1.11.6

Currying

 

1.11.6

1.11.6
TypeInstantiation   1.11.7

TypeInstantiation

 

1.11.7

1.11.7
LazyObjectLiteralInitialization   1.11.8
LazyObjectLiteralInitialization   1.11.8

LazyObjectLiteralInitialization

 
1.11.8

1.11.8

1.11.8
ClassesareUseful   1.11.9

ClassesareUseful

 

1.11.9

1.11.9
AvoidExportDefault   1.11.10

AvoidExportDefault

 

1.11.10

1.11.10
LimitPropertySetters   1.11.11

LimitPropertySetters

 

1.11.11

1.11.11
nullisbad   1.11.12

nullisbad

 

1.11.12

1.11.12
outFilecaution   1.11.13

outFilecaution

 

1.11.13

1.11.13
JQuerytips   1.11.14

JQuerytips

 

1.11.14

1.11.14
staticconstructors   1.11.15

staticconstructors

 

1.11.15

1.11.15
singletonpattern   1.11.16

singletonpattern

 

1.11.16

1.11.16
Functionparameters   1.11.17

Functionparameters

 

1.11.17

1.11.17
Truthy   1.11.18

Truthy

 

1.11.18

1.11.18
GenericsinTSX   1.11.19

GenericsinTSX

 

1.11.19

1.11.19
BuildToggles   1.11.20

BuildToggles

 

1.11.20

1.11.20

StyleGuide

StyleGuide
 

1.12

1.12

CommonErrors

CommonErrors
 

1.13

1.13

TypeScriptCompilerInternals

TypeScriptCompilerInternals
 

1.14

1.14
Program   1.14.1

Program

 

1.14.1

1.14.1
AST 1.14.2

AST

1.14.2

1.14.2
TIP:VisitChildren   1.14.2.1

TIP:VisitChildren

 

1.14.2.1

1.14.2.1
TIP:SyntaxKindenum   1.14.2.2

TIP:SyntaxKindenum

 

1.14.2.2

1.14.2.2
Trivia   1.14.2.3

Trivia

 

1.14.2.3

1.14.2.3
Scanner   1.14.3

Scanner

 

1.14.3

1.14.3
Parser   1.14.4

Parser

 

1.14.4

1.14.4
ParserFunctions   1.14.4.1

ParserFunctions

 

1.14.4.1

1.14.4.1
Binder   1.14.5

Binder

 

1.14.5

1.14.5
BinderFunctions   1.14.5.1

BinderFunctions

 

1.14.5.1

1.14.5.1
BinderDeclarations   1.14.5.2

BinderDeclarations

 

1.14.5.2

1.14.5.2
BinderContainer   1.14.5.3

BinderContainer

 

1.14.5.3

1.14.5.3
BinderSymbolTable   1.14.5.4

BinderSymbolTable

 

1.14.5.4

1.14.5.4
BinderErrorReporting   1.14.5.5

BinderErrorReporting

 

1.14.5.5

1.14.5.5
Checker   1.14.6

Checker

 

1.14.6

1.14.6
CheckerDiagnostics   1.14.6.1

CheckerDiagnostics

 

1.14.6.1

1.14.6.1
CheckerErrorReporting   1.14.6.2

CheckerErrorReporting

 

1.14.6.2

1.14.6.2

Emitter

Emitter
 

1.14.7

1.14.7
EmitterFunctions   1.14.7.1

EmitterFunctions

 

1.14.7.1

1.14.7.1
EmitterSourceMaps 1.14.7.2

EmitterSourceMaps

1.14.7.2

1.14.7.2

Contributing

Contributing
 

1.14.8

1.14.8

Introduction

TypeScriptDeepDive

I'vebeenlookingattheissuesthatturnupcommonlywhenpeoplestartusingTypeScript.

ThisisbasedonthelessonsfromStackOverflow/DefinitelyTypedandgeneralengagement

Reviews

Thanksforthewonderfulbook.Learnedalotfromit.(link) ItsprobablytheBestTypeScriptbookoutthere.GoodJob(link) Lovehowpreciseandcleartheexamplesandexplanationsare!(link) Forthelow,lowpriceoffree,yougetpagesofpureawesomeness.Chockfullofsource codeexamplesandclear,conciseexplanations,TypeScriptDeepDivewillhelpyou learnTypeScriptdevelopment.(link)

Justabigthankyou(link ) link)

Thisgitbookgotmyprojectgoingpronto.Fluenteasyread5stars.(link)

GetStarted

Ifyouareheretoreadthebookonlinegetstarted.

OtherOptions

Youcanalsodownloadoneofthefollowing:

SpecialThanks

Alltheamazingcontributors

Share

Introduction

GettingStarted

GettingStarted GettingStartedwithTypeScript TypeScriptVersion GettingStartedWithTypeScript

GettingStartedwithTypeScript

TypeScriptVersion

GettingStartedWithTypeScript

TypeScriptcompilesintoJavaScript.JavaScriptiswhatyouareactuallygoingtoexecute

(eitherinthebrowserorontheserver).Soyouaregoingtoneedthefollowing:

alm .Also lotsofother IDESsupportitaswell ) TypeScriptVersion Insteadofusingthe stable

TypeScriptVersion

InsteadofusingthestableTypeScriptcompilerwewillbepresentingalotofnewstuffinthis

bookthatmaynotbeassociatedwithaversionnumberyet.Igenerallyrecommendpeople

tousethenightlyversionbecausethecompilertestsuiteonlycatchesmorebugsover

time.

Youcaninstallitonthecommandlineas

npm install -g typescript@next

GettingStarted

Andnowthecommandline

e.g.

tsc
tsc

willbethelatestandgreatest.VariousIDEssupportittoo,

alm
alm

alwaysshipswiththelatestTypeScriptversion.

Youcanaskvscodetousethisversionbycreating

followingcontents:

.vscode/settings.json

withthe

{

"typescript.tsdk": "./node_modules/typescript/lib"

}

GettingtheSourceCode

Thesourceforthisbookisavailableinthebooksgithubrepository

becopiedintoalmandyoucanplaywiththemasis.Forcodesamplesthatneedadditional

setup(e.g.npmmodules),wewilllinkyoutothecodesamplebeforepresentingthecode.

e.g.

this/will/be/the/link/to/the/code.ts

// This will be the code under discussion

WithadevsetupoutofthewayletsjumpintoTypeScriptsyntax.

WhyTypeScript

WhyTypeScript

TherearetwomaingoalsofTypeScript:

ProvideanoptionaltypesystemforJavaScript.

ProvideplannedfeaturesfromfutureJavaScripteditionstocurrentJavaScriptengines

Thedesireforthesegoalsismotivatedbelow.

TheTypeScripttypesystem

Youmightbewondering"WhyaddtypestoJavaScript?"

Typeshaveprovenabilitytoenhancecodequalityandunderstandability.Largeteams

(google,microsoft,facebook)havecontinuallyarrivedatthisconclusion.Specifically:

Typesincreaseyouragilitywhendoingrefactoring.Itsbetterforthecompilertocatch

errorsthantohavethingsfailatruntime.

Typesareoneofthebestformsofdocumentationyoucanhave.Thefunctionsignature

isatheoremandthefunctionbodyistheproof.

Howevertypeshaveawayofbeingunnecessarilyceremonious.TypeScriptisvery

particularaboutkeepingthebarriertoentryaslowaspossible.Here'show:

YourJavaScriptisTypeScript

TypeScriptprovidescompiletimetypesafetyforyourJavaScriptcode.Thisisnosurprise

givenitsname.Thegreatthingisthatthetypesarecompletelyoptional.YourJavaScript

code .js .js
code
.js
.js

filecanberenamedtoa

.ts
.ts

fileandTypeScriptwillstillgiveyoubackvalid

equivalenttotheoriginalJavaScriptfile.TypeScriptisintentionallyandstrictlya

supersetofJavaScriptwithoptionalTypechecking.

TypescanbeImplicit

TypeScriptwilltrytoinferasmuchofthetypeinformationasitcaninordertogiveyoutype

safetywithminimalcostofproductivityduringcodedevelopment.Forexample,inthe

followingexampleTypeScriptwillknowthatfooisoftype

erroronthesecondlineasshown:

number
number

belowandwillgivean

WhyTypeScript

var foo = 123; foo = '456'; // Error: cannot assign `string` to `number`

// Is foo a number or a string?

Thistypeinferenceiswellmotivated.Ifyoudostufflikeshowninthisexample,then,inthe

restofyourcode,youcannotbecertainthat

turnupofteninlargemulti-filecodebases.Wewilldeepdiveintothetypeinferencerules

later.

foo
foo

isa

number
number

ora

string
string

.Suchissues

TypescanbeExplicit

Aswe'vementionedbefore,TypeScriptwillinferasmuchasitcansafely,howeveryoucan

useannotationsto:

1. Helpalongthecompiler,andmoreimportantlydocumentstuffforthenextdeveloper

whohastoreadyourcode(thatmightbefutureyou!).

2. Enforcethatwhatthecompilersees,iswhatyouthoughtitshouldsee.Thatisyour

understandingofthecodematchesanalgorithmicanalysisofthecode(donebythe

compiler).

TypeScriptusespostfixtypeannotationspopularinotheroptionallyannotatedlanguages

(e.g.ActionScriptandF#).

var foo: number = 123;

Soifyoudosomethingwrongthecompilerwillerrore.g.:

var foo: number = '123'; // Error: cannot assign a `string` to a `number`

WewilldiscussallthedetailsofalltheannotationsyntaxsupportedbyTypeScriptinalater

chapter.

Typesarestructural

Insomelanguages(specificallynominallytypedones)statictypingresultsinunnecessary

ceremonybecauseeventhoughyouknowthatthecodewillworkfinethelanguage

semanticsforceyoutocopystuffaround.ThisiswhystufflikeautomapperforC#isvitalfor

C#.InTypeScriptbecausewereallywantittobeeasyforJavaScriptdeveloperswitha

WhyTypeScript

minimumcognitiveoverload,typesarestructural.Thismeansthatducktypingisafirstclass

languageconstruct.Considerthefollowingexample.Thefunction

anythingthatcontainsallthethings(

iTakePoint2D

willaccept

x
x

and

y
y

)itexpects:

interface Point2D { x: number; y: number;

}

interface Point3D { x: number; y: number; z: number;

}

var point2D: Point2D = { x: 0, y: 10 } var point3D: Point3D = { x: 0, y: 10, z: 20 } function iTakePoint2D(point: Point2D) { /* do something */ }

iTakePoint2D(point2D); // exact match okay iTakePoint2D(point3D); // extra information okay iTakePoint2D({ x: 0 }); // Error: missing information `y`

TypeerrorsdonotpreventJavaScriptemit

TomakeiteasyforyoutomigrateyourJavaScriptcodetoTypeScript,evenifthereare

compilationerrors,bydefaultTypeScriptwillemitvalidJavaScriptthebestthatitcan.e.g.

var foo = 123; foo = '456'; // Error: cannot assign a `string` to a `number`

willemitthefollowingjs:

var foo = 123; foo = '456';

SoyoucanincrementallyupgradeyourJavaScriptcodetoTypeScript.Thisisverydifferent

fromhowmanyotherlanguagecompilersworkandyetanotherreasontomoveto

TypeScript.

Typescanbeambient

AmajordesigngoalofTypeScriptwastomakeitpossibleforyoutosafelyandeasilyuse

existingJavaScriptlibrariesinTypeScript.TypeScriptdoesthisbymeansofdeclaration.

TypeScriptprovidesyouwithaslidingscaleofhowmuchorhowlittleeffortyouwanttoput

WhyTypeScript

inyourdeclarations,themoreeffortyouputthemoretypesafety+codeintelligenceyou

get.NotethatdefinitionsformostofthepopularJavaScriptlibrarieshavealreadybeen

writtenforyoubytheDefinitelyTypedcommunitysoformostpurposeseither:

1. Thedefinitionfilealreadyexists.

2. Orattheveryleast,youhaveavastlistofwellreviewedTypeScriptdeclaration

templatesalreadyavailable

Asaquickexampleofhowyouwouldauthoryourowndeclarationfile,consideratrivial

exampleofjquery.Bydefault(asistobeexpectedofgoodJScode)TypeScriptexpectsyou

todeclare(i.e.use

var
var

somewhere)beforeyouuseavariable

$('.awesome').show(); // Error: cannot find name `$`

AsaquickfixyoucantellTypeScriptthatthereisindeedsomethingcalled

$ :
$
:

declare var $:any; $('.awesome').show(); // Okay!

Ifyouwantyoucanbuildonthisbasicdefinitionandprovidemoreinformationtohelp

protectyoufromerrors:

declare var $:{ (selector:string)=>any;

}; $('.awesome').show(); // Okay! $(123).show(); // Error: selector needs to be a string

WewilldiscussthedetailsofcreatingTypeScriptdefinitionsforexistingJavaScriptindetail

lateronceyouknowmoreaboutTypeScript(e.g.stufflike

interface

andthe

any ).
any
).

FutureJavaScript=>Now

TypeScriptprovidesanumberoffeaturesthatareplannedinES6forcurrentJavaScript

engines(thatonlysupportES5etc).Thetypescriptteamisactivelyaddingthesefeatures

andthislistisonlygoingtogetbiggerovertimeandwewillcoverthisinitsownsection.But

justasaspecimenhereisanexampleofaclass:

WhyTypeScript

class Point {

constructor(public x: number, public y: number) {

}

add(point: Point) { return new Point(this.x + point.x, this.y + point.y);

}

}

var p1 = new Point(0, 10); var p2 = new Point(10, 20); var p3 = p1.add(p2); // {x:10,y:30}

andthelovelyfatarrowfunction:

var inc = (x)=>x+1;

Summary

InthissectionwehaveprovidedyouwiththemotivationanddesigngoalsofTypeScript.

WiththisoutofthewaywecandigintothenittygrittydetailsofTypeScript.

JavaScript

YourJavaScriptisTypeScript

Therewere(andwillcontinuetobe)alotofcompetitorsinSomesyntaxtoJavaScript

compilers.TypeScriptisdifferentfromtheminthatYourJavaScriptisTypeScript.Here'sa

diagram:

YourJavaScriptisTypeScript .Here'sa diagram: Howeveritdoesmeanthat youneedtolearnJavaScript

HoweveritdoesmeanthatyouneedtolearnJavaScript(thegoodnewsisyouonlyneedto

learnJavaScript).TypeScriptisjuststandardizingallthewaysyouprovidegood

documentationonJavaScript.

Justgivingyouanewsyntaxdoesn'thelpfixbug(lookingatyouCoffeeScript).

Creatinganewlanguageabstractsyoutoofarfromyourruntimes,communities

(lookingatyouDart).

TypeScriptisjustJavaScriptwithdocs.

JavaScript

MakingJavaScriptBetter

TypeScriptwilltrytoprotectyoufromportionsofJavaScriptthatneverworked(soyoudon't

needtorememberthisstuff):

[]

+ []; // JavaScript will give you "" (which makes little sense), TypeScript will er

ror

// // other things that are nonsensical in JavaScript // - don't give a runtime error (making debugging hard)

// - but TypeScript will give a compile time error (making debugging unnecessary) // {} + []; // JS : 0, TS Error

[] + {}; // JS : "[object Object]", TS Error

{} + {}; // JS : NaN, TS Error "hello" - 1; // JS : NaN, TS Error

EssentiallyTypeScriptislintingJavaScript.Justdoingabetterjobatitthanotherlintersthat

don'thavetypeinformation.

YoustillneedtolearnJavaScript

ThatsaidTypeScriptisverypragmaticaboutthefactthatyoudowriteJavaScriptsothere

aresomethingsaboutJavaScriptthatyoustillneedtoknowinordertonotbecaughtoff-

guard.Letsdiscussthemnext.

Awful

JavaScripttheawfulparts

Herearesomeawful(misunderstood)partsofJavaScriptthatyoumustknow.

Note:TypeScriptisasupersetofJavaScript.Justwithdocumentationthatcanactually

beusedbycompilers/IDEs;)

NullandUndefined

Factisyouwillneedtodealwithboth.Justcheckforeitherwith

==
==

check.

/// Imagine you are doing `foo.bar == undefined` where bar can be one of:

console.log(undefined == undefined); // true console.log(null == undefined); // true console.log(0 == undefined); // false console.log('' == undefined); // false console.log(false == undefined); // false

Recommend

makeadistinctionbetweenthetwo.

== null
== null

tocheckforboth

undefined

or

null
null

.Yougenerallydon'twantto

undefined

RememberhowIsaidyoushoulduse

Don'tuseitforrootlevelthings.Instrictmodeifyouuse

geta

== null
== null

.Ofcourseyoudo(causeIjustsaidit^).

foo
foo

and

foo
foo

isundefinedyou

ReferenceError

exceptionandthewholecallstackunwinds.

Youshouldusestrictmode

modules

andinfacttheTScompilerwillinsertitforyouifyouuse

moreonthoselaterinthebooksoyoudon'thavetobeexplicitaboutit:)

Sotocheckifavariableisdefinedornotatagloballevelyounormallyuse

typeof :
typeof
:

if (typeof someglobal !== 'undefined') { // someglobal is now safe to use console.log(someglobal);

}

this

Awful

Anyaccessto

actuallycalled.Itiscommonlyreferredtoasthe

this
this

keywordwithinafunctionisactuallycontrolledbyhowthefunctionis

calling context

.

Hereisanexample:

function foo() { console.log(this);

}

foo(); // logs out the global e.g. `window` in browsers let bar = { foo

}

bar.foo(); // Logs out `bar` as `foo` was called on `bar`

Sobemindfulofyourusageof

callingcontextuseanarrowfunction,moreonthatlater.

this
this

.Ifyouwanttodisconnect

Next

this
this

inaclassfromthe

That'sit.ThosearethesimplemisunderstoodportionsofJavaScriptthatstillresultin

variousbugsfordevelopersthatarenewtothelanguage.

Closure

Closure

ThebestthingthatJavaScriptevergotwasclosures.AfunctioninJavaScripthasaccessto

anyvariablesdefinedintheouterscope.Closuresarebestexplainedwithexamples:

function outerFunction(arg) { var variableInOuterFunction = arg; function bar() { console.log(variableInOuterFunction);
function outerFunction(arg) {
var variableInOuterFunction = arg;
function bar() {
console.log(variableInOuterFunction); // Access a variable from the outer scope
}
// Call the local function to demonstrate that it has access to arg
bar();
}
outerFunction("hello closure"); // logs hello closure!

Youcanseethattheinnerfunctionhasaccesstoavariable(variableInOuterFunction)from

theouterscope.Thevariablesintheouterfunctionhavebeenclosedby(orboundin)the

innerfunction.Hencethetermclosure.Theconceptinitselfissimpleenoughandpretty

intuitive.

Nowtheawesomepart:Theinnerfunctioncanaccessthevariablesfromtheouterscope

evenaftertheouterfunctionhasreturned.Thisisbecausethevariablesarestillboundin

theinnerfunctionandnotdependentontheouterfunction.Againlet'slookatanexample:

function outerFunction(arg) { var variableInOuterFunction = arg; return function() { console.log(variableInOuterFunction);

}

}

var innerFunction = outerFunction("hello closure!");

// Note the outerFunction has returned innerFunction(); // logs hello closure!

Reasonwhyitsawesome

Itallowsyoutocomposeobjectseasilye.g.therevealingmodulepattern:

Closure

function createCounter() { let val = 0; return { increment() { val++ }, getVal() { return val }

}

}

let counter = createCounter(); counter.increment(); console.log(counter.getVal()); // 1 counter.increment(); console.log(counter.getVal()); // 2

Atahighlevelitisalsowhatmakessomethinglikenodejspossible(don'tworryifitdoesn't

clickinyourbrainrightnow.Itwilleventually):

// Pseudo code to explain the concept server.on(function handler(req, res) { loadData(req.id).then(function(data) { // the `res` has been closed over and is available res.send(data);

});

})

FutureJavaScriptNow

FutureJavaScript:Now

OneofthemainsellingpointsofTypeScriptisthatitallowsyoutouseabunchoffeatures

fromES6andbeyondincurrent(ES3andES5level)JavaScriptengines(likecurrent

browsersandNodeJS).Herewedeepdiveintowhythesefeaturesareusefulfollowedby

howthesefeaturesareimplementedinTypeScript.

Note:NotallofthesefeaturesareslatedforimmediateadditiontoJavaScriptbutprovide

greatutilitytoyourcodeorganizationandmaintenance.Alsonotethatyouarefreetoignore

anyoftheconstructsthatdon'tmakesenseforyourproject,althoughyouwillendupusing

mostofthemeventually;)

Classes

Classes

Thereasonwhyit'simportanttohaveclassesinJavaScriptasafirstclassitemisthat:

1. Classesofferausefulstructuralabstraction

2. Providesaconsistentwayfordeveloperstouseclassesinsteadofeveryframework

(emberjs,reactjsetc)comingupwiththeirownversion.

3. ObjectOrientedDevelopersalreadyunderstandclasses.

FinallyJavaScriptdeveloperscanhave

class
class

.HerewehaveabasicclasscalledPoint:

class Point { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y;

}

add(point: Point) { return new Point(this.x + point.x, this.y + point.y);

}

}

var p1 = new Point(0, 10); var p2 = new Point(10, 20); var p3 = p1.add(p2); // {x:10,y:30}

ThisclassgeneratesthefollowingJavaScriptonES5emit:

var Point = (function () { function Point(x, y) { this.x = x; this.y = y;

}

Point.prototype.add = function (point) { return new Point(this.x + point.x, this.y + point.y);

}; return Point; })();

ThisisafairlyidiomatictraditionalJavaScriptclasspatternnowasafirstclasslanguage

construct.

Inheritance

Classes

ClassesinTypeScript(likeotherlanguages)supportsingleinheritanceusingthe

keywordasshownbelow:

extends
extends

class Point3D extends Point { z: number; constructor(x: number, y: number, z: number) { super(x, y); this.z = z;

}

add(point: Point3D) { var point2D = super.add(point); return new Point3D(point2D.x, point2D.y, this.z + point.z);

}

}

Ifyouhaveaconstructorinyourclassthenyoumustcalltheparentconstructorfromyour

constructor(TypeScriptwillpointthisouttoyou).Thisensuresthatthestuffthatitneedsto

seton

wanttodoinyourconstructor(hereweaddanothermember

this
this

getsset.Followedbythecallto

super
super

youcanaddanyadditionalstuffyou

z ).
z
).
Notethatyouoverrideparentmemberfunctionseasily(hereweoverride add thefunctionalityofthesuperclassinyourmembers(using
Notethatyouoverrideparentmemberfunctionseasily(hereweoverride
add
thefunctionalityofthesuperclassinyourmembers(using
super.
syntax).

)andstilluse

Statics

TypeScriptclassessupport

Anaturalplacetoput(andaccess)themisontheclassitselfandthatiswhatTypeScript

does:

static
static

propertiesthataresharedbyallinstancesoftheclass.

class Something { static instances = 0; constructor() { Something.instances++;

}

}

var s1 = new Something(); var s2 = new Something(); console.log(Something.instances); // 2

Youcanhavestaticmembersaswellasstaticfunctions.

AccessModifiers

Classes

TypeScriptsupportsaccessmodifiers

theaccessibilityofa

public , private
public
, private
class
class

memberasshownbelow:

and

protected

whichdetermine

accessibleon

public
public
private
private
 

protected

classinstances

yes

no

no

class

yes

yes

yes

classchildren

yes

no

yes

Ifanaccessmodifierisnotspecifieditisimplicitly

natureofJavaScript.

public
public

asthatmatchestheconvinient

Notethatatruntime(inthegeneratedJS)thesehavenosignificancebutwillgiveyou

compiletimeerrorsifyouusethemincorrectly.Anexampleofeachisshownbelow:

class FooBase { public x: number; private y: number; protected z: number;

}

// EFFECT ON INSTANCES var foo = new FooBase(); foo.x; // okay foo.y; // ERROR : private foo.z; // ERROR : protected

// EFFECT ON CHILD CLASSES class FooChild extends FooBase { constructor() { super(); this.x; // okay this.y; // ERROR: private this.z; // okay

}

}

Asalwaysthesemodifiersworkforbothmemberpropertiesandmemberfunctions.

Abstract

abstract

canbethoughtofasanaccessmodifier.Wepresentitseparatelybecause

opposedtothepreviouslymentionedmodifiersitcanbeona

oftheclass.Havingan

directlyinvokedandachildclassmustprovide.

class
class

aswellasanymember

abstract

modifierprimarilymeansthatsuchfunctionalitycannotbe

abstract
abstract

classescannotbedirectlyinstantiated.Insteadtheusermustcreatesome

Classes

class abstract
class
abstract

thatinheritfromthe

abstract class

.

memberscannotbedirectlyaccessedandachildclassmustprovidethe

functionality.

Constructorisoptional

Theclassdoesnotneedtohaveaconstructor.e.g.thefollowingisperfectlyfine.

class Foo {} let foo = new Foo();

Defineusingconstructor

Havingamemberinaclassandinitializingitlikebelow:

class Foo { x: number; constructor(x:number) { this.x = x;

}

}

issuchacommonpatternthatTypeScriptprovidesashorthandwhereyoucanprefixthe

memberwithanaccessmodifieranditisautomaticallydeclaredontheclassandcopied

fromtheconstructor.Sothepreviousexamplecanbere-writtenas(notice

public
public
x:number ):
x:number
):

class Foo {

constructor(public x:number) {

}

}

Propertyinitializer

ThisisaniftyfeaturesupportedbyTypeScript(fromES7actually).Youcaninitializeany

memberoftheclassoutsidetheclassconstructor,usefultoprovidedefault(notice

= [] )
= []
)
members
members

Classes

class Foo { members = []; // Initialize directly add(x) { this.members.push(x);

}

}

ClassesEmit

WhatsupwiththeIIFE

Thejsgeneratedfortheclasscouldhavebeen:

function Point(x, y) { this.x = x; this.y = y;

}

Point.prototype.add = function (point) { return new Point(this.x + point.x, this.y + point.y);

};

ThereasonitswrappedinanImmediately-InvokedFunctionExpression(IIFE)i.e.

(function () {

// BODY

return Point; })();

hastodowithinheritance.ItallowsTypeScripttocapturethebaseclassasavariable

_super
_super

e.g.

var Point3D = (function (_super) {

extends(Point3D,

_super);

function Point3D(x, y, z) { _super.call(this, x, y); this.z = z;

}

Point3D.prototype.add = function (point) { var point2D = _super.prototype.add.call(this, point); return new Point3D(point2D.x, point2D.y, this.z + point.z);

}; return Point3D; })(Point);

NoticethattheIIFEallowsTypeScripttoeasilycapturethebaseclass

variableandthatisusedconsistentlyintheclassbody.

extends

Point
Point

ina

_super
_super

YouwillnoticethatassoonasyouinheritaclassTypeScriptalsogeneratesthefollowing

function:

ClassesEmit

var

extends

= this

extends

|| function (d, b) {

for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];

function

()

prototype

{ this.constructor = d; } = b.prototype;

d.prototype = new

();

};

Here d things:
Here
d
things:

referstothederivedclassand

b
b

referstothebaseclass.Thisfunctiondoestwo

1. copiesthestaticmembersofthebaseclassontothechildclassi.e.

if (b.hasOwnProperty(p)) d[p] = b[p];

for (var p in b)

2. setsupthechildclassfunction'sprototypetooptionallylookupmembersontheparent's

i.e.effectivelyd.prototype proto = b.prototype

d.prototype

proto

= b.prototype

Peoplerarelyhavetroubleunderstanding1,butmanypeoplestrugglewith2.soan

explanationisinorder

d.prototype

proto

= b.prototype

AfterhavingtutoredmanypeopleaboutthisIfindthefollowingexplanationtobesimplest.

Firstwewillexplainhowthecodefrom

extends

isequivalenttothesimple

d.prototype

proto

= b.prototype

,andthenwhythislineinitselfissignificant.To

understandallthisyouneedtoknowthesethings:

1. proto 2. prototype 3. effectof new on 4. effectof new on
1.
proto
2.
prototype
3.
effectof
new
on
4.
effectof
new
on
this prototype
this
prototype

insidethecalledfunction

and

proto

AllobjectsinJavaScriptcontaina

inolderbrowsers(sometimesdocumentationreferstothismagicalpropertyas

proto

member.Thismemberisoftennotaccessible

[[prototype]] (e.g. obj.property
[[prototype]]
(e.g.
obj.property

).Ithasoneobjective:Ifapropertyisnotfoundonanobjectduringlookup

)thenitislookedupat

obj

proto

property

.Ifitisstillnotfound

then

null.ThisexplainswhyJavaScriptissaidtosupportprototypalinheritanceoutofthebox.

Thisisshowninthefollowingexample,whichyoucanruninthechromeconsoleornodejs:

obj

proto

proto

property

tilleither:itisfoundorthelatest

proto

itselfis

ClassesEmit

var foo = {} // setup on foo as well as foo foo.bar = 123;
var foo = {}
// setup on foo as well as foo
foo.bar = 123;
proto
foo
proto
bar
= 456;
console.log(foo.bar); // 123
delete foo.bar; // remove from object
console.log(foo.bar); // 456
delete foo
proto
bar;
// remove from foo
proto
console.log(foo.bar); // undefined

Coolsoyouunderstand

JavaScripthaveapropertycalled

proto prototype
proto
prototype

.Anotherusefulinformationisthatall

andthatithasamember

function constructor
function
constructor

sin

pointingbacktothefunction.Thisisshownbelow:

function Foo() { } console.log(Foo.prototype); // {} i.e. it exists and is not undefined console.log(Foo.prototype.constructor === Foo); // Has a member called `constructor` p ointing back to the function

Nowletslookateffectof

thecalledfunctionisgoingtopointtothenewlycreatedobjectthatwillbereturnedfromthe

function.It'ssimpletoseeifyoumutateapropertyon

new
new

on

this
this

insidethecalledfunction.Basically

this
this

inside

insidethefunction:new on this insidethecalledfunction .Basically this inside function Foo () { this .bar = 123 ;

function Foo() { this.bar = 123;

}

// call with the new operator var newFoo = new Foo(); console.log(newFoo.bar); // 123

Nowtheonlyotherthingyouneedtoknowisthatcalling

new
new

onafunctioncopiesthe

prototype

ofthefunctionintothe

proto

ofthenewlycreatedobjectthatisreturned

fromthefunctioncall.Hereiscodeyoucanruntocompletelyunderstandit:

function Foo() { }

var foo = new Foo();

console.log(foo

proto

=== Foo.prototype); // True!

That'sit.Nowlookatthefollowingstraightoutof

theselines:

extends

.I'vetakethelibertytonumber

ClassesEmit

1 function

2 prototype

3 d.prototype = new

() { this.constructor = d; }

= b.prototype;

();

Readingthisfunctioninreversethe

d.prototype = new

()

online3effectivelymeans

d.prototype = {

proto

:

prototype}

(becauseoftheeffectof

on= { proto : prototype} (becauseoftheeffectof prototype and proto ),combineitwiththepreviousline(i.e.line2

prototype

and

proto

),combineitwiththepreviousline(i.e.line2

get

d.prototype = {

proto

: b.prototype}

.

prototype

= b.prototype;

)you

Butwaitwewanted

d.prototype

proto

i.e.justtheprotochangedandmaintaintheold

d.prototype.constructor

.Thisiswherethesignificanceofthefirstline(i.e.

function

()

{

this.constructor = d; }

)comesin.Herewewilleffectivelyhave

d.prototype = {

proto

:

prototype,

d.constructor = d}

(becauseoftheeffectof

new
new

on

insidethecalledprototype, d.constructor = d} (becauseoftheeffectof new on function).Sosincewerestore mutatedisthe

function).Sosincewerestore

mutatedisthe

d.prototype.constructor

,theonlythingwehavetruly

proto

hence

d.prototype

proto

= b.prototype

.

d.prototype

proto

= b.prototype

significance

Thesignificanceisthatitallowsyoutoaddmemberfunctionstoachildclassandinherit

othersfromthebaseclass.Thisisdemonstratedbythefollowingsimpleexample:

function Animal() { } Animal.prototype.walk = function () { console.log('walk') };

function Bird() { }

Bird.prototype

Bird.prototype.fly = function () { console.log('fly') };

proto

= Animal.prototype;

var bird = new Bird(); bird.walk(); bird.fly();

Basically

the

lookedupfrom

bird.fly

willbelookedupfrom

pointto

bird

proto

fly

)and

bird.walk

(as

).

(rememberthat

new
new

makes

bird

proto

Bird.prototype

(aninheritedmember)willbe

and

bird

proto

proto

walk

==

Animal.prototype

bird

proto

== Bird.prototype

bird

proto

proto

ClassesSuper

super

Notethatifyoucall

below:

super
super

onachildclassitisredirectedtothe

prototype

asshown

class Base { log() { console.log('hello world'); }

}

class Child extends Base { log() { super.log() };

}

generates:

var Base = (function () { function Base() {

}

Base.prototype.log = function () { console.log('hello world'); }; return Base; })(); var Child = (function (_super) {

extends(Child,

_super);

function Child() { _super.apply(this, arguments);

}

Child.prototype.log = function () { _super.prototype.log.call(this); }; return Child; })(Base);

Notice

_super.prototype.log.call(this)

.

Thismeansthatyoucannotuse

this .
this
.
super
super

onmemberproperties.Insteadyoushouldjustuse

class Base { log = () => { console.log('hello world'); }

}

class Child extends Base { logWorld() { this.log() };

}

andthe .log( 'hello world' ); } } class Child extends Base { logWorld() { this .log() };

Child
Child

classyou

ClassesSuper

AlsoNotethatTypeScriptwillwarnyouifyoutrytomisuse

super :
super
:

module quz { class Base { log = () => { console.log('hello world'); }

}

class Child extends Base { // ERROR : only `public` and `protected` methods of base class are accessible via `super` logWorld() { super.log() };

}

}

ArrowFunctions

ArrowFunctionsArrowFunctions Tip:ArrowFunctionNeed Tip:ArrowFunctionDanger Tip:Librariesthatuse this Tip:ArrowFunctioninheritance

Tip:ArrowFunctionNeedArrowFunctions ArrowFunctions Tip:ArrowFunctionDanger Tip:Librariesthatuse this Tip:ArrowFunctioninheritance

Tip:ArrowFunctionDanger

Tip:LibrariesthatuseArrowFunctions Tip:ArrowFunctionNeed Tip:ArrowFunctionDanger this Tip:ArrowFunctioninheritance ArrowFunctions

this
this

Tip:ArrowFunctioninheritance

ArrowFunctions

Lovinglycalledthefatarrow(because

calledalambdafunction(becauseofotherlanguages).Anothercommonlyusedfeatureis

thefatarrowfunction

->
->

isathinarrowand

=>
=>

isafatarrow)andalso

()=>something

.Themotivationforafatarrowis:

1. Youdon'tneedtokeeptyping

2. Itlexicallycapturesthemeaningof

function this arguments
function
this
arguments

3. Itlexicallycapturesthemeaningof

Foralanguagethatclaimstobefunctional,inJavaScriptyoutendtobetyping

quitealot.Thefatarrowmakesitsimpleforyoutocreateafunction

function

var inc = (x)=>x+1;

this
this

hastraditionallybeenapainpointinJavaScript.Asawisemanoncesaid"Ihate

JavaScriptasittendstolosethemeaningof

capturingthemeaningof

class:

this
this

alltooeasily".Fatarrowsfixitby

this
this

fromthesurroundingcontext.ConsiderthispureJavaScript

function Person(age) { this.age = age this.growOld = function() { this.age++;

}

}

var person = new Person(1);

setTimeout(person.growOld,1000);

setTimeout(function() { console.log(person.age); },2000); // 1, should have been 2

Ifyourunthiscodeinthebrowser

this
this

withinthefunctionisgoingtopointto

window
window

because

window
window

isgoingtobewhatexecutesthe

growOld
growOld

function.Fixistouseanarrow

function:

ArrowFunctions

function Person(age) { this.age = age this.growOld = () => { this.age++;

}

}

var person = new Person(1);

setTimeout(person.growOld,1000);

setTimeout(function() { console.log(person.age); },2000); // 2

Thereasonwhythisworksisthereferenceto

outsidethefunctionbody.ThisisequivalenttothefollowingJavaScriptcode(whichiswhat

youwouldwriteyourselfifyoudidn'thaveTypeScript):

this
this

iscapturedbythearrowfunctionfrom

function Person(age) { this.age = age var _this = this;

// capture this

this.growOld = function() {

_this.age++;

}

// use the captured this

}

var person = new Person(1);

setTimeout(person.growOld,1000);

setTimeout(function() { console.log(person.age); },2000); // 2

NotethatsinceyouareusingTypeScriptyoucanbeevensweeterinsyntaxandcombine

arrowswithclasses:

class Person { constructor(public age:number) {} growOld = () => { this.age++;

}

}

var person = new Person(1);

setTimeout(person.growOld,1000);

setTimeout(function() { console.log(person.age); },2000); // 2

Tip:ArrowFunctionNeed

Beyondthetersesyntax,youonlyneedtousethefatarrowifyouaregoingtogivethe

functiontosomeoneelsetocall.Effectively:

ArrowFunctions

var growOld = person.growOld; // Then later someone else calls it:

growOld();

Ifyouaregoingtocallityourself,i.e.

person.growOld();

then

this
this

isgoingtobethecorrectcallingcontext(inthisexample

person ).
person
).

Tip:ArrowFunctionDanger

Infactifyouwant

isthecasewithcallbacksusedbylibrarieslikejquery,underscore,mochaandothers.Ifthe

documentationmentionsfunctionson

insteadofafatarrow.Similarlyifyouplantouse

this
this

tobethecallingcontextyoushouldnotusethearrowfunction.This

this
this

thenyoushouldprobablyjustusea

function

arguments

don'tuseanarrowfunction.

Tip:Arrowfunctionswithlibrariesthatuse

this
this

Manylibrariesdothise.g

willuse

toaccessthelibrarypassed

variablelike

jQuery
jQuery

iterables(oneexamplehttp://api.jquery.com/jquery.each/)

this
this

topassyoutheobjectthatitiscurrentlyiteratingover.Inthiscaseifyouwant

this
this

aswellasthesurroundingcontextjustuseatemp

likeyouwouldintheabsenceofarrowfunctions.

_self
_self

let _self = this; something.each(function() { console.log(_self); // the lexically scoped value console.log(this); // the library passed value

});

Tip:Arrowfunctionsandinheritance

Ifyouhaveaninstancemethodasanarrowfunctionthenitsgoeson

onlyone

prototypemembers).Youcaneasilygetarounditbycreatingacopyofthemethodbefore

overridingitinthechild.

this super ( super
this
super
( super

.Sincethereis

onlyworkson

this
this

suchfunctionscannotparticipateinacallto

ArrowFunctions

class Adder { // This function is now safe to pass around add = (b: string): string => { return this.a + b;

}

}

class ExtendedAdder extends Adder { // Create a copy of parent before creating our own private superAdd = this.add; // Now create our override add = (b: string): string => { return this.superAdd(b);

}

}

RestParameters

RestParameters

Restparameters(denotedby

acceptmultipleargumentsinyourfunctionandgetthemasanarray.Thisisdemonstratedin

thebelowexample.

argumentName

forthelastargument)allowyoutoquickly

function iTakeItAll(first, second, console.log(allOthers);

}

iTakeItAll('foo', 'bar'); // [] iTakeItAll('foo', 'bar', 'bas', 'qux'); // ['bas','qux']

allOthers)

{

Restparameterscanbeusedinanyfunctionbeit

function / ()=> / class member .
function
/ ()=>
/ class member
.

let

let

var
var

VariablesinJavaScriptarefunctionscoped.Thisisdifferentfrommanyother

languages(C#/Javaetc.)wherethevariablesareblockscoped.Ifyoubringablockscoped

mindsettoJavaScriptyouwouldexpectthefollowingtoprint

123
123

,insteaditwillprint

456
456

var foo = 123; if (true) { var foo = 456;

}

console.log(foo); // 456

Thisisbecause

insidetheifblockasitisoutsidetheifblock.Thisisacommonsourceoferrorsin

{
{

doesnotcreateanewvariablescope.Thevariable

foo
foo

isthesame

JavaScriptprogram.ThisiswhyTypeScript(andES6)introducesthe let keywordtoallow
JavaScriptprogram.ThisiswhyTypeScript(andES6)introducesthe
let
keywordtoallow
youtodefinevariableswithtrueblockscope.Thatisifyouuse
let
insteadof
var
youget

atrueuniqueelementdisconnectedfromwhatyoumighthavedefinedoutsidethescope.

Thesameexampleisdemonstratedwith

let :
let
:

let foo = 123; if (true) { let foo = 456;

}

console.log(foo); // 123

Anotherplacewhere

let
let

wouldsaveyoufromerrorsisloops.

var index = 0; var array = [1, 2, 3]; for (let index = 0; index < array.length; index++) { console.log(array[index]);

}

console.log(index); // 0

Inallsinceritywefinditbettertouse

fornewandexistingmulti-lingualdevelopers.

let
let

wheneverpossibleasitleadstolessersurprises

Functionscreateanewscope

Sincewementionedit,we'dliketodemonstratethatfunctionscreateanewvariablescope

inJavaScript.Considerthefollowing:

let

var foo = 123; function test() { var foo = 456;

}

test(); console.log(foo); // 123

Thisbehavesasyouwouldexpect.Withoutthisitwouldbeverydifficulttowritecodein

JavaScript.

GeneratedJS

TheJSgeneratedbyTypeScriptissimplerenamingofthe

alreadyexistsinthesurroundingscope.E.g.thefollowingisgeneratedasiswithasimple

replacementof

let
let

variableifasimilarname

var
var

with

let :
let
:

if (true) { let foo = 123;

}

// becomes //

if (true) { var foo = 123;

}

Howeverifthevariablenameisalreadytakenbythesurroundingscopethenanewvariable

nameisgeneratedasshown(notice

_foo ):
_foo
):

var foo = '123'; if (true) { let foo = 123;

}

// becomes //

var foo = '123'; if (true) { var _foo = 123; // Renamed

}

letinclosures

AcommonprogramminginterviewquestionforaJavaScriptdeveloperiswhatisthelogof

thissimplefile:

let

var funcs = []; // create a bunch of functions for (var i = 0; i < 3; i++) { funcs.push(function() { console.log(i);

})

}

// call them for (var j = 0; j < 3; j++) { funcs[j]();

}

Onewouldhaveexpectedittobe

functions.Reasonisthatallthreefunctionsareusingthevariable

andatthetimeweexecutethem(inthesecondloop)thevalueof

terminationconditionforthefirstloop).

0,1,2
0,1,2

.Surprisinglyitisgoingtobe

3 i i willbe 3
3
i
i
willbe
3

forallthree

fromtheouterscope

(that'sthe

Afixwouldbetocreateanewvariableineachloopspecifictothatloopiteration.Aswe've

learntbeforewecancreateanewvariablescopebycreatinganewfunctionand

immediatelyexecutingit(i.e.theIIFEpatternfromclasses

asshownbelow:

(function() { /* body */ })();

)

var funcs = []; // create a bunch of functions for (var i = 0; i < 3; i++) { (function() { var local = i; funcs.push(function() { console.log(local);

})

})();

}

// call them for (var j = 0; j < 3; j++) { funcs[j]();

}

Herethefunctionscloseover(hencecalleda

)thelocalvariable(conveniently

named

local
local
closure i .
closure
i
.

)andusethatinsteadoftheloopvariable

Notethatclosurescomewithaperformanceimpact(theyneedtostorethesurrounding

state)

TheES6

let
let

keywordinaloopwouldhavethesamebehaviorasthepreviousexample

let

var funcs = []; // create a bunch of functions for (let