ENJOYINGLARGESCALE
BROWSERDEVELOPMENT
joost@de-vries․name
codestar.nl
joost-de-vries
@jouke
TYPESCRIPT
WHEREI'MCOMINGFROMScala
SystemsthatrunonJVMandUnixflavour
Systemsforcoreproducts
Functionalprogramming
Reactiveprogramming
WorryingaboutDockerstuffandproxiesandclustersand...
Browserdevelopmentusedtofeel
likeanalienworld
TYPESCRIPTMadeaTypescriptbuildtool:https://github.com/joost-de-vries/sbt-typescript
Donefullstackprojectswithfrontend:
Typescript
RxJs
Angular2
PokingaroundalotintheTScompilersourcecode
JAVASCRIPTBUTSMARTERYougetimmediatefeedbackthroughtheredsea
Yougetacodecompletiondropdownwhiletyping
Youcanclickthroughtothedefinition
Youcanrefactorwithconfidenceacrossallyourfiles
Allbecauseoftypes
Soifwedroneonabouttypesit'sbecauseoftheease
ofuseitenables.
TYPESinterfacePerson{firstName:string;lastName:string;}
functiongreeter(person:Person){return"Hello,"+person.firstName+""+person.lastName;}
constuser={firstName:"Jane",lastname:"User"};
document.body.innerHTML=greeter(user);//willshowaredsea.lastnameiscamelcase
Addsomesimpletypetoafunction
JAVASCRIPTBUTSMARTERAnyJavascriptisvalidTypescriptinitially
Youcanincreaseyourcontrolgradually
byaddingtypes
byrulingouterrorpronepatterns
Verypractical:
increasecontrolstepbystep
RULINGOUTERRORPRONEPATTERNS
{"compilerOptions":{"target":"ES5","module":"system","lib":["es6","dom"],
/*settingsthatflagpotentialerrors*/"noEmitOnError":true,"noImplicitAny":true,"noImplicitReturns":true,"noFallthroughCasesInSwitch":true,"forceConsistentCasingInFileNames":true,"noImplicitThis":true},
Turnoncompileroptionsstepbystep
import*asReactfrom'react';import{Modal,ModalContent}from'../modal';importLoginFormfrom'./login-form';
interfaceILoginModalPropsextendsReact.Props<any>{isVisible:boolean;isPending:boolean;hasError:boolean;onSubmit:()=>void;};
exportdefaultfunctionLoginModal({isVisible,isPending,hasError,onSubmit}:ILoginModalProps){return(<ModalisVisible={isVisible}><ModalContent><h1className="mt0">Login</h1>
<LoginFormisPending={isPending}hasError={hasError}onSubmit={onSubmit}/>
It'sthejavascriptofthefuture
rightnow
..transpiledintoES5orES3
youcanstartgraduallyandchooseyourpreferedamountofcontrol
letsuits=["hearts","spades","clubs","diamonds"];
functionpickCard(x){//...}
letmyDeck=[{suit:"diamonds",card:2},{suit:"spades",card:10},{suit:"harts",card:4}];
letpickedCard2=pickCard(15);
typeSuit="hearts"|"spades"|"clubs"|"diamonds";
letsuits:Suit[]=["hearts","spades","clubs","diamonds"];
typeRank=1|2|3|4|5|6|7|8|9|10|11|12|13
interfaceCard{suit:Suitcard:Rank}typeDeck=Card[]
functionpickCard(x:Deck|Rank):any{//...}
letmyDeck:Card[]=[{suit:"diamonds",card:2},{suit:"spades",card:10},{suit:"harts",card:4}];//willshowanerror
letpickedCard2=pickCard(15);//willshowanerror
Withtypesadded
varSnake=(function(_super){__extends(Snake,_super);functionSnake(name){_super.call(this,name);}Snake.prototype.move=function(distanceInMeters){if(distanceInMeters===void0){distanceInMeters=5;}console.log("Slithering...");_super.prototype.move.call(this,distanceInMeters);};returnSnake;}(Animal));
varsam=newSnake("SammythePython");sam.move();
Themodulepatterntoprevent
globalscope
Emulatinginheritance
Happy!
classSnakeextendsAnimal{constructor(privatename:string){}
move(distanceInMeters=5){console.log(`${this.name}slithering...`)super.move(distanceInMeters)}}
constsam=newSnake("SammythePython")
sam.move()
MOVINGAWAYFROMTHE'AWFULPARTSOFJAVASCRIPT'
globalvariables ES6
scopes ES6
semicoloninsertion Typescript
reservedkeywords ES6+/-
unicode ES6
typeof Typescript
parseInt esLint
floatingpoint esLint
NaN esLint
phonyarrays ES6
MOVINGAWAYFROMTHE'BADPARTSOFJAVASCRIPT'
== tsLint
within Typescript
eval esLint
continue ES6+/-
switchfallthrough Typescript
Block-lessStatements esLint
++ esLint
BitwiseOperators ?
functionexpression ES6
typedwrappers ?
THEJOURNEYAWAYFROMTHEBADPARTS
OFJAVASCRIPTModuleloaders;AMD,CommonJs
jsHint,esLint,tsLint
Ecmascriptupdates:ES6,ES7
Types!Typescript,Flowtype,...
Typesarethenextstep
CHALLENGESFORTYPESINJAVASCRIPTPATTERNS
functionbuildName(firstName,lastName){if(lastName)returnfirstName+""+lastName;elsereturnfirstName;}
buildName("Jan");
Allfunctionargumentsare
optionalinJavascript
functionbuildName(firstName:string,lastName?:string){if(lastName)//type:string|undefinedreturnfirstName+""+lastName;//type:stringelsereturnfirstName;}
buildName("Jan")
Typeguardstripsawayundefined
fromthetypeoftheoptional
argument
functioncreateName(name){if(name.length){returnname.join("");}else{returnname;}}vargreetingMessage="Greetings,"+createName(["Sam","Smith"]);
TypicalJavascript
Dealwithdifferenttypesof
arguments
typeNameOrNameArray=string|string[];
functioncreateName(name:NameOrNameArray){if(typeofname==="string"){//type:stringorstring[]returnname;//type:string}else{returnname.join("");//type:string[]}}
vargreetingMessage=`Greetings,${createName(["Sam","Smith"])}`;
TypicalJavascript
'Or'typesarecalleduniontypes
GREATTYPESCRIPTSUPPORTSublimeText
Atom
VisualCode
IntelliJ/Webstorm
Eclipse
VisualStudio
TScompileroffersalanguageapi
thateditorsandIDEscanuse
functionpadLeft(value:string,padding:string|number){//...}
constindentedString=padLeft("Helloworld",true);//error
Uniontypes
interfaceBird{fly();layEggs();}
interfaceFish{swim();layEggs();}
functiongetSmallPet():Fish|Bird{//...}
letpet=getSmallPet();pet.layEggs();//okaypet.swim();//errors Uniontypes
ABOUTTSTYPESclassAnimal{feet:number;constructor(name:string,numFeet:number){}}
classSize{feet:number;constructor(numFeet:number){}}
leta:Animal;lets:Size;
a=s;//OKs=a;
Typesarestructuralinsteadofthe
morecommonnominaltyping
typeEasing="ease-in"|"ease-out"|"ease-in-out";
classUIElement{animate(dx:number,dy:number,easing:Easing){if(easing==="ease-in"){//...}elseif(easing==="ease-out"){}elseif(easing==="ease-in-out"){}else{//error!shouldnotpassnullorundefined.}}}
letbutton=newUIElement();button.animate(0,0,"ease-in");button.animate(0,0,"uneasy");//error:"uneasy"isnotallowedhere Uniontypesandliteraltypes
Apowerfulcombination
functionbar(x:string|number){if(typeofx==="number"){return;}x;//typeofxisstringhere} Controlflowanalysis
NULLANDUNDEFINEDAWARETYPES
//Compiledwith--strictNullChecksfunctionparseNumber(json:string):number|undefined
letx:number|undefined;lety:number;
x=parseNumber(json);//Oky=parseNumber(json);//Compileerrorif(x){y=x;//Okxhastypenumberhere}
Nomore'undefinedisnota
function'!
interfaceSquare{kind:"square";size:number;}
interfaceRectangle{kind:"rectangle";width:number;height:number;}
typeShape=Square|Rectangle|Circle;
functionarea(s:Shape){switch(s.kind){case"square":returns.size*s.size;//typeisSquarecase"rectangle":returns.width*s.height;//Rectanglecase"circle":returnMath.PI*s.radius*s.radius;}}
ADTsandpatternmatching!
main=App.beginnerProgram{model=optOut,update=update,view=view}
typealiasModel={notifications:Bool,autoplay:Bool,location:Bool}
optOut:ModeloptOut=ModelTrueTrueTrue
Ifyoudon'twanttobuildon
Javascript
IfyouwanttodomoreFunctional
Programming
ALTERNATIVESBabel+Flowtype
Coffeescript
ScalaJs
Elm
Purescript
Clojurescript
Java!
...MostlanguagescompiletoJSnowadays
TYPESCRIPTVSFLOWTYPETS Flow
bettereditorsupport
moreopendevelopment
soundtypesystem
controlflowanalysis controlflowanalysis
null,undefinedaware null,undefinedaware
taggedunions taggedunionsBothgreatforbrowserde
v
TS2.0hascaughtupwithalotofstandoutFlowf
eatures
DON'TUSETSIFyoudon'tlikeJavascript
youdon'twanttosetupabuild
youdislikeanythingfromMicrosoft
it'snotthatmuchcodeandtheteamisjustyou
SONewversionsofEcmascriptarereallynice
Youcanusethemrightnow
Typescripthelpswhenyourteamandyourcodebasegrows
YoucanuseexistingJScode
There'salotoftoolsupport
Lotsofresourcesonlinetogetstarted
Opensourceandcrossplatform