1. typescript handbook€¦ · the typescript handbook is intended to be a comprehensive document...
TRANSCRIPT
-
1. TypeScriptHandbook2. TableofContents3. TheTypeScriptHandbook4. BasicTypes5. Interfaces6. Functions7. LiteralTypes8. UnionsandIntersectionTypes9. Classes10. Enums11. Generics
-
ThiscopyoftheTypeScripthandbookwasgeneratedonWednesday,March3,2021againstcommit422674withTypeScript4.2.
https://github.com/microsoft/TypeScript-Website/tree/422674https://www.typescriptlang.org//docs/handbook/release-notes/typescript-4-2.html
-
TheTypeScriptHandbook
AboutthisHandbook
Over20yearsafteritsintroductiontotheprogrammingcommunity,JavaScriptisnowoneofthemostwidespreadcross-platformlanguagesevercreated.Startingasasmallscriptinglanguageforaddingtrivialinteractivitytowebpages,JavaScripthasgrowntobealanguageofchoiceforbothfrontendandbackendapplicationsofeverysize.Whilethesize,scope,andcomplexityofprogramswritteninJavaScripthasgrownexponentially,theabilityoftheJavaScriptlanguagetoexpresstherelationshipsbetweendifferentunitsofcodehasnot.CombinedwithJavaScript'sratherpeculiarruntimesemantics,thismismatchbetweenlanguageandprogramcomplexityhasmadeJavaScriptdevelopmentadifficulttasktomanageatscale.
Themostcommonkindsoferrorsthatprogrammerswritecanbedescribedastypeerrors:acertainkindofvaluewasusedwhereadifferentkindofvaluewasexpected.Thiscouldbeduetosimpletypos,afailuretounderstandtheAPIsurfaceofalibrary,incorrectassumptionsaboutruntimebehavior,orothererrors.ThegoalofTypeScriptistobeastatictypecheckerforJavaScriptprograms-inotherwords,atoolthatrunsbeforeyourcoderuns(static)andensuresthatthetypesoftheprogramarecorrect(typechecked).
IfyouarecomingtoTypeScriptwithoutaJavaScriptbackground,withtheintentionofTypeScriptbeingyourfirstlanguage,werecommendyoufirststartreadingthedocumentationonJavaScriptattheMozillaWebDocs.Ifyouhaveexperienceinotherlanguages,youshouldbeabletopickupJavaScriptsyntaxquitequicklybyreadingthehandbook.
https://developer.mozilla.org/docs/Web/JavaScript/Guide
-
HowisthisHandbookStructured
Thehandbookissplitintotwosections:
TheHandbook
TheTypeScriptHandbookisintendedtobeacomprehensivedocumentthatexplainsTypeScripttoeverydayprogrammers.Youcanreadthehandbookbygoingfromtoptobottomintheleft-handnavigation.
Youshouldexpecteachchapterorpagetoprovideyouwithastrongunderstandingofthegivenconcepts.TheTypeScriptHandbookisnotacompletelanguagespecification,butitisintendedtobeacomprehensiveguidetoallofthelanguage'sfeaturesandbehaviors.
Areaderwhocompletesthewalkthroughshouldbeableto:
Readandunderstandcommonly-usedTypeScriptsyntaxandpatternsExplaintheeffectsofimportantcompileroptionsCorrectlypredicttypesystembehaviorinmostcasesWritea.d.tsdeclarationforasimplefunction,object,orclass
Intheinterestsofclarityandbrevity,themaincontentoftheHandbookwillnotexploreeveryedgecaseorminutiaeofthefeaturesbeingcovered.Youcanfindmoredetailsonparticularconceptsinthereferencearticles.
ReferenceFiles
ThereferencesectionisbuilttoprovidearicherunderstandingofhowaparticularpartofTypeScriptworks.Youcanreadittop-to-bottom,buteachsectionaimstoprovideadeeperexplanationofasingleconcept-meaningthereisnoaimforcontinuity.
Non-Goals
-
Non-GoalsTheHandbookisalsointendedtobeaconcisedocumentthatcanbecomfortablyreadinafewhours.Certaintopicswon'tbecoveredinordertokeepthingsshort.
Specifically,theHandbookdoesnotfullyintroducecoreJavaScriptbasicslikefunctions,classes,andclosures.Whereappropriate,we'llincludelinkstobackgroundreadingthatyoucanusetoreaduponthoseconcepts.
TheHandbookalsoisn'tintendedtobeareplacementforalanguagespecification.Insomecases,edgecasesorformaldescriptionsofbehaviorwillbeskippedinfavorofhigh-level,easier-to-understandexplanations.Instead,thereareseparatereferencepagesthatmorepreciselyandformallydescribemanyaspectsofTypeScript'sbehavior.ThereferencepagesarenotintendedforreadersunfamiliarwithTypeScript,sotheymayuseadvancedterminologyorreferencetopicsyouhaven'treadaboutyet.
Finally,theHandbookwon'tcoverhowTypeScriptinteractswithothertools,exceptwherenecessary.TopicslikehowtoconfigureTypeScriptwithwebpack,rollup,parcel,react,babel,closure,lerna,rush,bazel,preact,vue,angular,svelte,jquery,yarn,ornpmareoutofscope-youcanfindtheseresourceselsewhereontheweb.
GetStarted
BeforegettingstartedwithBasicTypes,werecommendreadingoneofthefollowingintroductorypages.TheseintroductionsareintendedtohighlightkeysimilaritiesanddifferencesbetweenTypeScriptandyourfavoredprogramminglanguage,andclearupcommonmisconceptionsspecifictothoselanguages.
TypeScriptforNewProgrammersTypeScriptforJavaScriptProgrammersTypeScriptforOOPProgrammersTypeScriptforFunctionalProgrammers
https://www.staging-typescript.org/docs/handbook/basic-types.htmlhttps://www.staging-typescript.org/docs/handbook/typescript-from-scratch.htmlhttps://www.staging-typescript.org/docs/handbook/typescript-in-5-minutes.htmlhttps://www.staging-typescript.org/docs/handbook/typescript-in-5-minutes-oop.htmlhttps://www.staging-typescript.org/docs/handbook/typescript-in-5-minutes-func.html
-
BasicTypesForprogramstobeuseful,weneedtobeabletoworkwithsomeofthesimplestunitsofdata:numbers,strings,structures,booleanvalues,andthelike.InTypeScript,wesupportthesametypesasyouwouldexpectinJavaScript,withanextraenumerationtypethrownintohelpthingsalong.
Boolean
Themostbasicdatatypeisthesimpletrue/falsevalue,whichJavaScriptandTypeScriptcallabooleanvalue.
letisDone:boolean=false;
Number
AsinJavaScript,allnumbersinTypeScriptareeitherfloatingpointvaluesorBigIntegers.Thesefloatingpointnumbersgetthetypenumber,whileBigIntegersgetthetypebigint.Inadditiontohexadecimalanddecimalliterals,TypeScriptalsosupportsbinaryandoctalliteralsintroducedinECMAScript2015.
letdecimal:number=6;lethex:number=0xf00d;letbinary:number=0b1010;letoctal:number=0o744;letbig:bigint=100n;
String
AnotherfundamentalpartofcreatingprogramsinJavaScriptforwebpagesandserversalikeisworkingwithtextualdata.Asinotherlanguages,weusethetype
https://www.typescriptlang.org/play/#code/DYUwLgBAlgzgIgewHYgFwQEYIaAhkiAXggDNdgYQBuIAhttps://www.typescriptlang.org/play/#code/PTAEAEBcEMCcHMCmkBcoCiBlATABjwFAA2yoAJogMYCWAttEWgHYCutARorKALygBsAbmKkAFogAezNp259cEgGa5cZYSUih21JnACe0jl16hc7AIy5L60gHtKMRqFZG5p2wHYALF5ubt8GgBOpp8lrhMgkAhttps://www.typescriptlang.org/play/#code/DYUwLgBAxg9sMCcBcEDOYEEsB2BzCAvBAEQBGwAriMQNwBQA9AxAA4LhiYgIC0mu2RCDqx4CQhADk7ACaSaQAhttps://www.typescriptlang.org/play/#code/DYUwLgBAZgrswDkCGBbEAuCBnMAnAlgHYDmEAvBAAYBCA9gEYR331HFi2GUDcAUKJCTEMEQjBT0QuchADMAdj4DsIQmFUBjETgIkZlABIh4tADQQUAT1GoQEfFggASAN6x4yNAF8AdL14AkgDk8BCSzi5CdgDUEACMXhCWIEi4jrTAACaiIAAekCicYAAWPjxAAhttps://www.typescriptlang.org/play/#code/DYUwLgBAZgrswDkCGBbEAuCBnMAnAlgHYDmEAvBAAYBCA9gEYR331HFi2GUDcAUKJCTEMEQjBT0QuchADMAdj4B6JRAC0GgMYwwGtf3DYQhMMc0icBEuV4QIAIgASIeLQA0EFAE9RqEBHwsBwgAaltoOEQ-UPD7ADoAHUIk+xi7ewBJAHJ4CElgsLsACiF-EIgARgBKNOCvECRcINpgABNREAAPSBROMAALOPtuIAhttps://www.typescriptlang.org/play/#code/DYUwLgBMCWDOYC4IDsCuBbARiATgbQF0IBeCPARgBoIAmagZgIG4ghttps://www.typescriptlang.org/play/#code/DYUwLgBMCWDOYC4IEEBOqCGBPAPAOwFcBbAIxFQD4IBeCAbQEYAaCAJhYGYBdAbiAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGY1oFAlACKQDGANgIbSSjmgAuArgA6nV0CeTkOrdoAHqgDaiOtACWAOwDmAGlCSGAWwBGMALoBuPGACSk8XXHlS4gF7VDOfqAC8oIQCIAFpFKk4j+QEYADFtB8AHkAaR1QfUNjUwtQQzjJYgQqYjpSdms7Bz95FzcPRwD8AFFYBCAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYME4BQAbSAF1AA9UBtRI6ASwDsBzAGlHoFcBbAIxgF0A3LlKgAvKAoAiABaR8+OJNYBGAAyDQIUAHkA0rhBgAtCYDG7IiaMGwe3Kbj1EcQgDoFjABSkK614nZuajomT2UASnChe0dnNw9vCmU+f0Dghi8IqKAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwBYCcBmdBWHNdItAKABtIAXUAD1QG1FroBLAOwHMAaUDgK4BbAEYwAugG4ydUAF5QjAEQALSBQpwlfAIwAGKaBCgA8gGkyIMAFpbAYwHVb1mYxzj5oJQHcEFACZK0mR2cByIcFQAdJpcABR0jPjiUdRwAMqsnPEAlDmSQAhttps://www.typescriptlang.org/play/#code/KYOwrgtgBAwg9gGzgJygbwFBSgJWAEwBosoBxZYUY7AIQTGGIF8MFgAXKAYwC5ZEUUALz8kyAHTlKIANxAhttps://www.typescriptlang.org/play/#code/KYOwrgtgBAwg9gGzgJygbwFBSgJWAEygF4oBGAGiygHFlhRLsAhBMYSgXwwWABcoAxgC5YiFMVFJkAOlr0QAbiAhttps://www.typescriptlang.org/play/#code/KYOwrgtgBAwg9gGzgJygbwFBSgJWAEygF4oBGAGiygHFlhRioAmS7AIQTGEYBZKBfDAmAAXKAGMAXLEQpG8JMgB0teiADcQAhttps://www.typescriptlang.org/play/#code/KYOwrgtgBAwg9gGzgJygbwFBSgJWAEygF4oBGAGiygHFlhRLsAhBMYSgXwwWABcoAxohQA5AIYRgALigBnXsgCWIAObFYw5AG0ATAF0A3BgwB6E1AAii2QAcEYgJ6yoAclr0QLjEJCzEwADokFQAKISRkcUkASgMgAhttps://www.typescriptlang.org/play/#code/DYUwLgBAdg9mDKBXATiAXBRUDWsDuUEAvBACwDcAULAiiMRAEQC2AhgJ4BG9rEAzmGQBLKAHMIIgSFYATRlUoB6RRADyAaQA0EGSABmIoWBDB2EXpxgxQrKNThJUDPa2B8Q5IAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGY1vVnnsAoAE0gGMAbAQ2klDLgDtEAXUAWyoE8AjSVAK6MA1ozgB3RgG5CIUAHJOvSPPpwBFYqD6gqoVtACWjAOYAaUHB4Arciws84cCpCqMLQ0gDNjkYhYRLFgALGFAWLgAHSERCBmY2KgA5AXY+aFRGVPTQAF4Obj4ZQkMvUAAKJR1cmvDoAUgASlAAb0JQUDkAFSjIAGUyI0i2UQlEcOCqNiq6Q3G9R2dXRlAxcXa1BN0AIScXN1RF-ZX8mZkOuT64C0M2MjcxNh09A2MTDfjWXT6WI1NUV6mPIFZQyAC+hBKZXKEWicDKMzytQARICTMjmm0LmAetEBkMRmtxiEpiCdHNdPpfm8PkwvlQfn8TADqUDToVIOdOmArjc7g84E86As9staVsqLslgdtKK3MCzoQwUAhttps://www.typescriptlang.org/play/#code/CYUwxgNghgTiAEAzArgOzAFwJYHtXwHMQMA1KCZEACgGsQBPALngGcMYtUCBKZqVegG4AUAHpR8APIBpADTw4GZDHwA3cpXg5E8AORFSGkLvhYW8VDgzwwAC3B1gwsHjat2zNhy7wAvIWIyCmoAIgBbegBldk4CEO5BIAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwFYDsBGAUADaQAuoBccikBAngCo0AOkAJqgIYB2NoAvKABYA3HhCgA8gGkANKACWAMwCSxAKIAPOYmKJQAWzkBzABalIm7aHaloAV07E5eyIQpVaDZiwB0ilRq0dAAoAShExKVliOAAxOXVWUHNA3SCAI1tSYmNIUABjOD1GOSJoUBY4SEROAHJSPJy8gGsQ10pqeiZWb2i4hJZQkUISUG1oOTziDy62UHsmzjgAd04+QRExianOrx7Y+NZBoAhttps://www.typescriptlang.org/play/#code/DYUwLgBMD20M4mATwCpIA4gCYC4IEMA7JCAXggG8BfAbgChRIsypYFk1MsA6fbgI24BjblnoB6cRAgA9APxAhttps://www.typescriptlang.org/play/#code/GYVwdgxgLglg9mABAdwIYCcwFUDOBTdACgEoAuRANzhgBNEBvAKEUQgRzgBs8A6TuAOaEARABUAFjByIpiALYBPFBjAwwA+Xhw5UAvMOIBuRgF8gAhttps://www.typescriptlang.org/play/#code/PTAEAEGcBcCcEsDG0BcoBmBDANpApgFDZ7SgCuAdmZJgEbFoBuA9vACagC85Fbe68CnjYBuAiFAB5ANKh46UAAMAtMpgJkAOTLZsAYQAWeRAGtIiuZFAVmpAObxGeCgUrU6xLtZ3YRQAhttps://www.typescriptlang.org/play/#code/PTAEDkHsBdQWwK4GMAWoCmAbAzu0B3PJAQwDtRjtsBLAc3OklGhXV1ADdiAna4gI0xsAhACghsBAC5QCUgBN0AM2ql080AF5ZC5avUBucelikZpBJkxbQFqwaAhttps://www.typescriptlang.org/play/#code/PTAEDEFcDsGMBcCWB7aoBOBTel3UdAOajSYBum6oAtpAM7wnKMAWAhhaGxpm7OwCMANplCZoAE1AAHZAXgAoAGYwEKNJXTJ0ACmqY6dNoUwAuUA3QFCASnOkKVAN4LQoeCy0B3Eph8BRdC1dfUNjTBsAbgUAXwUFEFAASWglTUwpLBw8dwBPaVFEOl9HZVUkVFAlNkQhHRtQFzcs3A0g7R0AIgBlZH0PayqakQlOqNj4xKg4CrQWvEGHShp6RmhmUHZObiw+QRExSRk5aEUVGfVQAiUCRHhMABlkZGl6+3JlptAvFlrRHXg6EgEUacRiQAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYAsBWAUACaQDGANgIbSSgBmArgHbEAuAlnA6MVec5ABRxUcAEYArEs1AAfUAzqlSASlQA3OKwIBuPHhCgA8gGk83SLwEBvUAAd4N1AAZQAXyU6zF-vMXvTPPn5GIhpWBkgCd1B9ACVIAFsEkRgAGlBgyFDwglBWRDk4KXJQRDoRZgBPG2o4GjkFUl1PQKw0P2aBACJEZmgwgHNO9oCBGnJSREh3IAhttps://www.typescriptlang.org/play/#code/DYUwLgBAzg9gtiAagQ2AVxALgmgdga1xgHdcIBeCAIjAAsBLKCRiZaMAJ3twHMqBuAFCDQkKJwAyIXnWy40cAEYgOFCAApYCFOhCsm4rrwCUAOlAza-IAhttps://www.typescriptlang.org/play/#code/DYUwLgBAzg9gtiAagQ2AVxALgmgdga1xgHdcIBeCAIjAAsBLKCRiZaMAJ3twHMqBuAFCDQkKJwAyIXnWy40cAEYgOFCAAoAPOK68AfLAQp0IAJQA6UDNr8gAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYME4BQAzAVwDsBjAFwEs5jRpIA3GRSAChVAGVzpLiBzAJSpuvAaADeuUHUjlC0WogB0iAA4AbSuVYAiXYOX0mSNoYBWcPnoMBuXAF9cuY8za6AFpA0a4oAO4IGgAmdkAhttps://www.typescriptlang.org/play/#code/GYVwdgxgLglg9mABAJwKYDdXIM6oBTYBci2UyMYA5gJTGnlWIDeAUIiqlCMktgHTYADgBsYUPACIJ1Pmkw58MgFZwKk6QG4WAXxYs5WXJIAWqYcLiIA7nGTCAJpqA
-
stringtorefertothesetextualdatatypes.JustlikeJavaScript,TypeScriptalsousesdoublequotes(")orsinglequotes(')tosurroundstringdata.
letcolor:string="blue";color='red';
Youcanalsousetemplatestrings,whichcanspanmultiplelinesandhaveembeddedexpressions.Thesestringsaresurroundedbythebacktick/backquote(`)character,andembeddedexpressionsareoftheform${expr}.
letfullName:string=`BobBobbington`;letage:number=37;letsentence:string=`Hello,mynameis${fullName}.
I'llbe${age+1}yearsoldnextmonth.`;
Thisisequivalenttodeclaringsentencelikeso:
letsentence:string="Hello,mynameis"+fullName+".\n\n"+"I'llbe"+(age+1)+"yearsoldnextmonth.";
Array
TypeScript,likeJavaScript,allowsyoutoworkwitharraysofvalues.Arraytypescanbewritteninoneoftwoways.Inthefirst,youusethetypeoftheelementsfollowedby[]todenoteanarrayofthatelementtype:
letlist:number[]=[1,2,3];
Thesecondwayusesagenericarraytype,Array:
letlist:Array=[1,2,3];
Tuple
-
Tuple
Tupletypesallowyoutoexpressanarraywithafixednumberofelementswhosetypesareknown,butneednotbethesame.Forexample,youmaywanttorepresentavalueasapairofastringandanumber:
//Declareatupletypeletx:[string,number];//Initializeitx=["hello",10];//OK//Initializeitincorrectlyx=[10,"hello"];//Error
Type'number'isnotassignabletotype'string'.Type'string'isnotassignabletotype'number'.
Whenaccessinganelementwithaknownindex,thecorrecttypeisretrieved:
//OKconsole.log(x[0].substring(1));
console.log(x[1].substring(1));
Property'substring'doesnotexistontype'number'.
Accessinganelementoutsidethesetofknownindicesfailswithanerror:
x[3]="world";
Tupletype'[string,number]'oflength'2'hasnoelementatindex'3'.
console.log(x[5].toString());
Objectispossibly'undefined'.Tupletype'[string,number]'oflength'2'hasnoelementatindex'5'.
Enum
AhelpfuladditiontothestandardsetofdatatypesfromJavaScriptistheenum.AsinlanguageslikeC#,anenumisawayofgivingmorefriendlynamestosetsofnumericvalues.
enumColor{Red,
-
Green,Blue,}letc:Color=Color.Green;
Bydefault,enumsbeginnumberingtheirmembersstartingat0.Youcanchangethisbymanuallysettingthevalueofoneofitsmembers.Forexample,wecanstartthepreviousexampleat1insteadof0:
enumColor{Red=1,Green,Blue,}letc:Color=Color.Green;
Or,evenmanuallysetallthevaluesintheenum:
enumColor{Red=1,Green=2,Blue=4,}letc:Color=Color.Green;
Ahandyfeatureofenumsisthatyoucanalsogofromanumericvaluetothenameofthatvalueintheenum.Forexample,ifwehadthevalue2butweren'tsurewhatthatmappedtointheColorenumabove,wecouldlookupthecorrespondingname:
enumColor{Red=1,Green,Blue,}letcolorName:string=Color[2];
//Displays'Green'console.log(colorName);
Unknown
-
Wemayneedtodescribethetypeofvariablesthatwedonotknowwhenwearewritinganapplication.Thesevaluesmaycomefromdynamiccontent–e.g.fromtheuser–orwemaywanttointentionallyacceptallvaluesinourAPI.Inthesecases,wewanttoprovideatypethattellsthecompilerandfuturereadersthatthisvariablecouldbeanything,sowegiveittheunknowntype.
letnotSure:unknown=4;notSure="maybeastringinstead";
//OK,definitelyabooleannotSure=false;
Ifyouhaveavariablewithanunknowntype,youcannarrowittosomethingmorespecificbydoingtypeofchecks,comparisonchecks,ormoreadvancedtypeguardsthatwillbediscussedinalaterchapter:
declareconstmaybe:unknown;//'maybe'couldbeastring,object,boolean,undefined,orothertypesconstaNumber:number=maybe;
Type'unknown'isnotassignabletotype'number'.
if(maybe===true){//TypeScriptknowsthatmaybeisabooleannowconstaBoolean:boolean=maybe;//So,itcannotbeastringconstaString:string=maybe;
Type'boolean'isnotassignabletotype'string'.}
if(typeofmaybe==="string"){//TypeScriptknowsthatmaybeisastringconstaString:string=maybe;//So,itcannotbeabooleanconstaBoolean:boolean=maybe;
Type'string'isnotassignabletotype'boolean'.}
Any
Insomesituations,notalltypeinformationisavailableoritsdeclarationwouldtakeaninappropriateamountofeffort.Thesemayoccurforvaluesfromcode
-
thathasbeenwrittenwithoutTypeScriptora3rdpartylibrary.Inthesecases,wemightwanttoopt-outoftypechecking.Todoso,welabelthesevalueswiththeanytype:
declarefunctiongetValue(key:string):any;//OK,returnvalueof'getValue'isnotcheckedconststr:string=getValue("myString");
TheanytypeisapowerfulwaytoworkwithexistingJavaScript,allowingyoutograduallyopt-inandopt-outoftypecheckingduringcompilation.
Unlikeunknown,variablesoftypeanyallowyoutoaccessarbitraryproperties,evenonesthatdon'texist.ThesepropertiesincludefunctionsandTypeScriptwillnotchecktheirexistenceortype:
letlooselyTyped:any=4;//OK,ifItExistsmightexistatruntimelooselyTyped.ifItExists();//OK,toFixedexists(butthecompilerdoesn'tcheck)looselyTyped.toFixed();
letstrictlyTyped:unknown=4;strictlyTyped.toFixed();
Objectisoftype'unknown'.
Theanywillcontinuetopropagatethroughyourobjects:
letlooselyTyped:any={};letd=looselyTyped.a.b.c.d;//^=letd:any
Afterall,rememberthatalltheconvenienceofanycomesatthecostoflosingtypesafety.TypesafetyisoneofthemainmotivationsforusingTypeScriptandyoushouldtrytoavoidusinganywhennotnecessary.
Void
voidisalittleliketheoppositeofany:theabsenceofhavinganytypeatall.Youmaycommonlyseethisasthereturntypeoffunctionsthatdonotreturnavalue:
-
functionwarnUser():void{console.log("Thisismywarningmessage");}
Declaringvariablesoftypevoidisnotusefulbecauseyoucanonlyassignnull(onlyif--strictNullChecksisnotspecified,seenextsection)orundefinedtothem:
letunusable:void=undefined;//OKif`--strictNullChecks`isnotgivenunusable=null;
NullandUndefined
InTypeScript,bothundefinedandnullactuallyhavetheirtypesnamedundefinedandnullrespectively.Muchlikevoid,they'renotextremelyusefulontheirown:
//Notmuchelsewecanassigntothesevariables!letu:undefined=undefined;letn:null=null;
Bydefaultnullandundefinedaresubtypesofallothertypes.Thatmeansyoucanassignnullandundefinedtosomethinglikenumber.
However,whenusingthe--strictNullChecksflag,nullandundefinedareonlyassignabletounknown,anyandtheirrespectivetypes(theoneexceptionbeingthatundefinedisalsoassignabletovoid).Thishelpsavoidmanycommonerrors.Incaseswhereyouwanttopassineitherastringornullorundefined,youcanusetheuniontypestring|null|undefined.
Uniontypesareanadvancedtopicthatwe'llcoverinalaterchapter.
Asanote:weencouragetheuseof--strictNullCheckswhenpossible,butforthepurposesofthishandbook,wewillassumeitisturnedoff.
Never
-
Never
Thenevertyperepresentsthetypeofvaluesthatneveroccur.Forinstance,neveristhereturntypeforafunctionexpressionoranarrowfunctionexpressionthatalwaysthrowsanexceptionoronethatneverreturns.Variablesalsoacquirethetypeneverwhennarrowedbyanytypeguardsthatcanneverbetrue.
Thenevertypeisasubtypeof,andassignableto,everytype;however,notypeisasubtypeof,orassignableto,never(exceptneveritself).Evenanyisn'tassignabletonever.
Someexamplesoffunctionsreturningnever:
//Functionreturningnevermustnothaveareachableendpointfunctionerror(message:string):never{thrownewError(message);}
//Inferredreturntypeisneverfunctionfail(){returnerror("Somethingfailed");}
//FunctionreturningnevermustnothaveareachableendpointfunctioninfiniteLoop():never{while(true){}}
Object
objectisatypethatrepresentsthenon-primitivetype,i.e.anythingthatisnotnumber,string,boolean,bigint,symbol,null,orundefined.
Withobjecttype,APIslikeObject.createcanbebetterrepresented.Forexample:
declarefunctioncreate(o:object|null):void;
//OKcreate({prop:0});create(null);
-
create(undefined);//Remember,undefinedisnotasubtypeofnull
Argumentoftype'undefined'isnotassignabletoparameteroftype'object|null'.
create(42);
Argumentoftype'42'isnotassignabletoparameteroftype'object|null'.create("string");
Argumentoftype'"string"'isnotassignabletoparameteroftype'object|null'.create(false);
Argumentoftype'false'isnotassignabletoparameteroftype'object|null'.
Generally,youwon'tneedtousethis.
Typeassertions
Sometimesyou'llendupinasituationwhereyou'llknowmoreaboutavaluethanTypeScriptdoes.Usually,thiswillhappenwhenyouknowthetypeofsomeentitycouldbemorespecificthanitscurrenttype.
Typeassertionsareawaytotellthecompiler"trustme,IknowwhatI'mdoing."Atypeassertionislikeatypecastinotherlanguages,butitperformsnospecialcheckingorrestructuringofdata.Ithasnoruntimeimpactandisusedpurelybythecompiler.TypeScriptassumesthatyou,theprogrammer,haveperformedanyspecialchecksthatyouneed.
Typeassertionshavetwoforms.
Oneistheas-syntax:
letsomeValue:unknown="thisisastring";
letstrLength:number=(someValueasstring).length;
Theotherversionisthe"angle-bracket"syntax:
letsomeValue:unknown="thisisastring";
letstrLength:number=(someValue).length;
Thetwosamplesareequivalent.Usingoneovertheotherismostlyachoiceof
-
preference;however,whenusingTypeScriptwithJSX,onlyas-styleassertionsareallowed.
Anoteaboutlet
Youmayhavenoticedthatsofar,we'vebeenusingtheletkeywordinsteadofJavaScript'svarkeywordwhichyoumightbemorefamiliarwith.TheletkeywordisactuallyanewerJavaScriptconstructthatTypeScriptmakesavailable.YoucanreadintheHandbookReferenceonVariableDeclarationsmoreabouthowletandconstfixalotoftheproblemswithvar.
AboutNumber,String,Boolean,SymbolandObject
ItcanbetemptingtothinkthatthetypesNumber,String,Boolean,Symbol,orObjectarethesameasthelowercaseversionsrecommendedabove.Thesetypesdonotrefertothelanguageprimitiveshowever,andalmostnevershouldbeusedasatype.
functionreverse(s:String):String{returns.split("").reverse().join("");}
reverse("helloworld");
Instead,usethetypesnumber,string,boolean,objectandsymbol.
functionreverse(s:string):string{returns.split("").reverse().join("");}
reverse("helloworld");
https://www.staging-typescript.org/docs/handbook/variable-declarations.html
-
InterfacesOneofTypeScript'scoreprinciplesisthattypecheckingfocusesontheshapethatvalueshave.Thisissometimescalled"ducktyping"or"structuralsubtyping".InTypeScript,interfacesfilltheroleofnamingthesetypes,andareapowerfulwayofdefiningcontractswithinyourcodeaswellascontractswithcodeoutsideofyourproject.
OurFirstInterface
Theeasiestwaytoseehowinterfacesworkistostartwithasimpleexample:
functionprintLabel(labeledObj:{label:string}){console.log(labeledObj.label);}
letmyObj={size:10,label:"Size10Object"};printLabel(myObj);
ThetypecheckerchecksthecalltoprintLabel.TheprintLabelfunctionhasasingleparameterthatrequiresthattheobjectpassedinhasapropertycalledlabeloftypestring.Noticethatourobjectactuallyhasmorepropertiesthanthis,butthecompileronlychecksthatatleasttheonesrequiredarepresentandmatchthetypesrequired.TherearesomecaseswhereTypeScriptisn'taslenient,whichwe'llcoverinabit.
Wecanwritethesameexampleagain,thistimeusinganinterfacetodescribetherequirementofhavingthelabelpropertythatisastring:
interfaceLabeledValue{label:string;}
functionprintLabel(labeledObj:LabeledValue){console.log(labeledObj.label);}
letmyObj={size:10,label:"Size10Object"};
https://www.typescriptlang.org/play/#code/GYVwdgxgLglg9mABABwE4zFAMgQwEYCmANgBRH7EEAmA8ngFYBciA3ouYUcwM5TpgBzRAF8AlKwBQiRBATc4RAgDoicAWQqLaDFZtEBuCcIkTFURAFsAnnXqIAvK0TcYALwLMAjAAYANO01mACIAZTcCRB9EWwJoIJFDNAxsTRJrWwMgAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgDJwEYQDYQCYBqc2ArigN4BQyy2mOAXMgM5hSgDmA3JQL6WUYJEAjDAA9iGQAHduHRZsACjqL8AeQwArJgpz4ipCAEpkVGgknNxuAHTZxHFfVx5NW+y+M9+lXGGQAWwBPd2QAXjMWYAAvCCYARgAGABpaFyYAIgBlWJRk5HcIUUzkXh5ZUDA9ZRD3byAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMoEcCucoQMID2IMwA5sgN4BQyyCBANgVAPwBcyAzmFKKQNw1kAd2AATMAAt2yEJgC2AI2iCAvlSoxMIBGGBE6uOJAzZcACnrEyHUznxESpAJQcKdRsw7deIAcns4DjklaGRVSiEGCDBZCGE7XGQAXkoPJigOACJhSWBILIAaAKMOAEYABgrwwVpgGGRLRzIAOnoM50jaWhB4xIg2zygUj2tSQYza8KF6xqsnFtEJSU7qbriErHsWwJH51qWpZAAqUYXDySn1WlwwTCgQDf61DWjY+QBPfr2jEy2LdztLzILKKBiIADWWXCzn4QAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwFYMEYBQBLAOwBcYAzAQwGNJQBlARwFcLpIBhOQs-Ac1ADeuUKCpwANggD8qRMWhFeAbmGgA7vgAmxABYzQhJgFsARjBUBfXLjJNCVYvi6i2FUoxZsAFGO59UHqwcXDy8AJSoAqISCLLyikqgQRSohqYwoBaCquKQxAaQaoFsoAC8gtGS0KgARGo6+KQ1ADRJrqjYAAydmSoi+GSgPiF8AHRUVWHZIiIgoACisLGgAArwAA4wxACeoADkEwh7oJpwkIgGcPmQAB74cqDOO5v7xcF+vHuqIoSFb+MxaBlaIfcZVPqZVQDIa+UKjDTaHRTIQzApFZhBUbJYGwsYI3SgABUILh+J0EKsIjYxCY0EIaLelmsuXyRm2bxxrncGO8UTEVVqJnE1AA1jVMmElEAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgAoHtRmQbwFDLJQRwAm6IANgJ7IAeAXMiAK4C2ARtANwFEnkqtak1aceeAL5Ahttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwFYAsAGAUAJYB2ALjAGYCGAxpKAApzEmgDeeoo0klAJnEQA2AT1AAPVEQCuAWwBGMANwcuPfkNHDJshdGUBfPCFABaM9SkkzJvIMgsADgEZUjZqAC8bcaic4ANKBa6Dig+srOAHRinqAYiqDGMPDQAIRAAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwFYAsb0GY8BOdbABlCwEZSsAoAG0gBdQBDVAOwFcBbAIxgBtALqgAvKEGUANOll5ZWYQG4GzUPFQAlSKwAmcDvQCeAQVitjAHm78YAPnFtVteINKiJlNMtAhQMPDQAISucAB0AA5ciAAWABQYAJS+-oEIofDhjBwA5kyxTtSkqWDpIbSsTvClAbAZQAhttps://www.typescriptlang.org/play/#code/DYUwLgBAhgXBB2BXAtgIxAJwNoF0IF4IsBGAGggCZyBmcgFhwG4AoUSDAezgCUQoATDvGABPAIIYMUEQB4kaTAD4C0FsygrO0AM4IU6bEyAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYAsBWdB2DATgCgBLAOwBcYAzAQwGNJQBlARwFd7pIBhOBVpkA5qADeJUKEZwANggD8qRFWiURAbimgA7mQAmVABbLQFTgFsARjG0BfEiVqcKjKmUEze9Gh268ABSyQqKo-jz8gsIiAJSo4jLyCCpqGpqgkfSoFjYwoPYSOrxUnNAURdLSsgrQqCExAHQ1CKAAPm2gAES8Bl0ANDrSWfXRoo36RsagikmhIhOGJqAAVHNNk8uoaAAMg9L2Dk5ykFSglgCeEbygALzekL6Q15CBiS1lqD2Qff16S8ZUABGHY7AqxTRAAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYAsBWdB2DATgCgBLAOwBcYAzAQwGNJQBlARwFd7pIBhOBVpkA5qADeJUKEZwANggD8qRFWiURAbimgA7mQAmVABbLQFTgFsARjG0BfEiVqcKjKmUEze9Gh268ABSyQqKo-jz8gsIiAJSo4jLyCCpqGpqgkfSoFjYwoPYSOrxUnNAURdLSsgrQqCExAHQ1CKAAPm2gAES8Bl0ANDrSWfXRoo36RsagikmhIhOGJqAAVHNNk8uoaAAMg9L2DiQgoAC054ycVOenJHKQVKCWAJ4RvKAAvN6QvpBvkIFEi0yqgepA+v09EtjKgAIw7HYFWKaIAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYAsBWdB2DATgCgBLAOwBcYAzAQwGNJQBlARwFd7pIBhOBVpkA5qADeJUKEZwANggD8qRFWiURAbimgA7mQAmVABbLQFTgFsARjG0BfEiVqcKjKmUEze9Gh268ABSyQqKo-jz8gsIiAJSo4jLyCCpqGpqgkfSoFjYwoPYSOrxUnNAURdLSsgrQqCExAHQ1CKAAPm2gAES8Bl0ANDrSWfXRoo36RsagikmhIhOGJqAAVHNNk8uoaAAMg9L2DiQgoAC054ycVOenJHKQVKCWAJ4RvKAAvN6QvpBvkIFEptjKgAIw7PagOAAByYZCoz1QO0aeEK9EQbC4kQE81imiAAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMoEcCucoQMID2IMwA5sgN4BQyyCBANgVAPwBcyAzmFKKQNw1kAd2AATMAAt2yEJgC2AI2iDaAbQAOUAhoByceRA7deIUgF0OcEAE9BAXyAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMoEcCucoQMID2IMwA5sgN4BQyyCBANgVAPwBcyAzmFKKQNw1kAd2AATMAAt2yEJgC2AI2iDaAbQAOUAhoByceRA7deIUgF0OcEAE9BAXypUYmEAjDAidXHEgZsuAAU9MRkHP44+EQkpACUHBR0jMzGPHz8yJFwHHJK0Mj2lEK4YJhQIEW0tPRMUBwhMQB0NczIAD5tyABEuGJdADRCtFn10WSNohKSyCxJoaQT4lLIAFRzTZPLHABMAAyDtPYOVAD0J8gAtFcImGBXF1QMEGBcWJEA8hoeRJzIALyUJJMMocHoQPr9ERLSQcACMu12BUETxe8hsEVw-28EF8EAxEECnDeuE+3xAnFi-CAAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwFYME4BQBLAOwBcYAzAQwGNJQBlARwFcLpIBhOQs-Ac1ADeuUKCpwANggD8qRMWhFeAbmGgA7vgAmxABYzQhJgFsARjBUBfXLjJNCVYvi6i2FUoxZsAFGO59UHqwcXDy8AJSoAqISCLLyikqgQRSohqYwoBaCqmzETNCE2SIiYpLQqL6hAHSlCKAAPvWgAERsms0ANKoiyRUhfFUa2jqgUtF+vINauqAAVOPVQzOoaAAMXSIWlrggoAC0B1RMxAd7uOKQxKCIzEEA8gAOjlyIoAC8gtGS+aitkO2ZFQXK5GACegTY7xckDckAhkC8N08kEez0IiDCSiAAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMoTlBALAYgVxAWQG8AoZZACgGcB7fLCALmRrClAHMAaN-AEaoO3Vu04guASlYC6dADYYQAbjIBfIAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMoTlBALAYgVxAWQG8AoZZACgGcB7fLCALmRrClAHMAaN-AEaoO3Vu04guASlYC6dADYYQAbjIBfMgHotyALQGE+MAb1klYZAFsAnukw5W9rHkII1ZW85zIAvMhg3MGA6EGp6RiQxEUk+GkFhCS5opJlkOUVlUgpkC2QoCHiFS38IpgA6GgwXWgSY6TVKArBGMIKiywA+fQBGNXUVIAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMoTlBALAYgVxAWQG8AoZZACgGcB7fLCALmRrClAHMAaN-AEaoO3Vu04guASlYC6dADYYQAbjIBfMgHotyALQGE+MAb1klYZAFsAnukw5W9rHkII1ZW85zIAvMhg3MGA6EGoaLDERST4aQSiJaVl5JTgw8koLZCgIOIVLfwiEADoaDBdaQSk1ShywRjCcvMsAPn0ARjV1FSAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMoTlBALAYgVxAWQG8AoZZACgGcB7fLCALmRrClAHMAaN-AEaoO3Vu04guASlYC6dADYYQAbjIBfMgHotyALQGE+MAb1klYZAFsAnukw5W9rHkII1ZW85zIAvMhg3MGA6EGoaLD4aQSlSCmQLZCgIaIVLfwiEADoaDBdaGLVKZLBGMOTUywA+fQBGNXUVIAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGY1oFAEsA7AFxgDMBDAY0lAGVJzpKALAMQFcDLQBvHUUAApEcdk0ipERaIQDmAGlCJ2AI1rS5kjQVkBKVCrhwANgwIBuHAF8cIUAFpHldkUf2cpoqAC2AT3qMLKgBTGyclJY4fiEsoAC8oKThRHhwBEKITIrKKrq8-KCeoNCQysZeCZmUAHSIDKHCqrqWAiVEYukARFIyOp2WVuZAAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMpiqA5gQSlOAT2QG8AoZZAbVABMIAPALmRAFcBbAI2gF0WAzhmwBuMgF8yZADYQwyDoTwFCLdJhC58RMYuVFkAXmoAiAEIB7LiYA0yEwDEoEWid5iZchYXWDhmo299QioABncgAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwBYCMBmAUCBIgC7QCWAxsQArwAOMxAngJIB2ZxZAhgDZkAvblzhtUAMz6JIeMm2IxJFSKACCHALZ9QAbzyhQbbhsioS5NgHMA3HgC+eWfMXdloACJxLoSAA8FbAAmiGqa2noGAEbQkJCBZqRyNvaOhACisAiocoF+SaAA7pwAFqDchgCuJuQUoOb5GmSWxcSglpCtTHAVZaAUcBp0vB2QvEx1kHTc0MIqzAygcOKhZFq8AIROCtBKKgBycMQA8gDW3OMRoADavqhsVZEwALqo6qt8tgY3CRaWLx5eWx2IAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwBYCMWBQBLAOwBcYAzAQwGNJQA5AVwFsAjGAEXyuPzkIugBPUAG9coUAG0iAE0gAPVImLQiAcwC6qQszbQA3ONAAbSITXEAFtt0x9oEKDgBrADQmzFy6HyJQFUB1WGCN+JkglFXV7Rxh4aHcrWmJBAAdaODJQAHIwyGyfP0I4Yn9QRAYWFPSnLKSfQjl5EIBfIAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgHIFcC2AjaB5KAZTClAHMARYBMYAexDigE9kBvAKGWQG1QATCAA8AXMgDOJcgF0xILLijIAPhKkgyAbi7IANhA1gAFnIXRNyAPSXkdANYAaPQbLHkwccjjJ5OaDsZMCDFJUg0La1tHHzgg909vUPIOAF8gAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwFYAsaBQBLAOwBcYAzAQwGNJQAlSCgEzkIBsBPAZWOiIHMAgrAodQAb1yhQ0Ri3ZiA2kSaQAHqkIBXALYAjGAF1UiXgIDcuAL65cbSMVA6Ow6KNQNmrTjz6EhImIAvKCKAESCbPg0YQA0oGEAQnB6YYaWzq6iimiGoCFhALIUbGwIHGHmoCCgMPDQAIRAAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMIBsD2CDWBJcaeJZAbwChlkEBXKKCcAFWAFsIAuZAETkgG5yAX3LkE6OAGdJaLLmRsADugjtwMjNnyFYiFBSq16jMC3ZdekZAF5kICAHcefCAAoAlIMOYQksFBoEMEwoVwALLhAaVgAjaAAaZFZI6LiodzIRISAhttps://www.typescriptlang.org/play/#code/PTAEAEGcBcCcEsDG0AKsD2AHApraBPASQDt5p4BDAG3gC8Lz1iAuUAM2smwCh5jpcHRNlABhKukQBrEgNhCRAb26hQiAK6xY2fgBV4AW2ysAIg2wBuFaC7R9RgBQATU+YCUrAG7p4TqwF9ubkQqCkhIMQlpUENMKmwjfgjxSRl+QQphUGVVDS0dO0NjUDMBUABeUGJsAHcS8wc3K1Vbe2xnVwE3bOtVaAALeEgAOjztPSKK0D9rQNymGFh1ZHRYB37WYnUDACNcABpQA03tvdhuxUD-IAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygOwAYCMBmUAmAFnwwIFYA2QgKBAkQBdoBLAYwYAV4AHGBgTwCSAO2YNmAQwA2zAF4TxcYagBm0xJFphwwuIIC23GazEBBYf1XrNzYQxhrWkUAGEpcVgGsXSxtACu7AigAN7UoKDCkADuoAAUABZw-tCowv76AEYwADSg+rb+9mkZ2dAAlADc1AC+1NSsUhKIiK7uXqDMhlKQ+pB2rW4e3r5MgQzBYRGsKdD9DAAqXZCoACIKkNXTowFB0IklWbn5h2XloXU1QAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMIBsD2CDWrMgDOYUArgmJlMgN4BQyyIEA7sgBQAWmpUAXE1IBbAEbQANMiGhSkASGFioASgEZsOAJLho8JAG46AXzp1QkWIhTrc2i3pT1GYYLnarkAN0zAAJoZM6GFIQCmACZAQoCDhIGxx2BkjKfjQsXHwiEnIU8STuXnlFCSTpBTlBUWg6D3i7XStaJOiwXhAmVmSqLh4oSTLZCGUA0wR0OEJCZAARYABzYDA4dHjkYCEAB3QIIQhwKbqdSyQmxgQCYjIKbs4iqr6pO6VlWhNnVwSXp0ZIi8xtgB0WDm7AARGIIBtkBCNqDhkkTIExhMpgBBEDLTBzVbrLY7PZgA7pLRHBynX5ZK4pLhPCSPSrPV5JFxuL5JM5-QHAsEsnDISi4OGGRiI0zbMDIXzzRbLZAAXki0ViEHi7FmCyWK2JkgAjAAmXUAdnh4uQcAxwPlipicWJ7HRmOx2uQhskAGY9cMgAhttps://www.typescriptlang.org/play/#code/PTAEAEGcBcCcEsDG0AKsD2AHApraBPASQDt5p4BDAG3gC8Lz1iAuUAM2smwCgQJj0hALaYaiMgEFi+Vhypdu8YtFwdE2UAGEq6RAGtNTGLACuydLFABvbqFDFsAd1AAKABboTsVsRNCARrgANKBCSiYqPn6BsACUrNq6eiQqsGrYANzcAL7cisqqFOpaOvophcU2duT6LvGgAG7o8AAmWbnciEbQJUkJpQbdpuaWALygiFQUkJC9+qDwIlTYQtjKs4llBWlFGlUTQ2bQFu5RAcGhZzGx1rnVSHp11rZ2B8SQ6MsAdDoA5i4AIkC2EwoGBmABsSydly2Sy3GWPUmSVA4wczk2jwAjAAmEJYgDsUM6Ay+NUeUKAAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMoAs4AcUG8BQyyCA9gDYlQBcyAzmFKAOYDc+AvvvqJLIiqgCOAVzhQUEAB6QQAE1ppMOZASK1gsiABkIIJmHQ0QwgLYAjaG074yEMHRFiUAXhXtkcBUNHi2tR+IAdKQUUMiuAERmZMIQEX4BEIHqmjp6BuHIAIwADCxAAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMoAs4AcUG8BQyyCA9gDYlQBcyAzmFKAOYDc+AvvvqJLIigAUIIVAxIBrPIWQ4QAdWAATMOhogArgFsARtDadu4aPCRoAjurhQUEAB6QQi2mkw4ANMiEixk5ASK0ShAAMsJMKmpaulD6XGQQYHQWVigAvH7syHDOqMnWbLR5EAB0pBRQyOkARNpk6hBVBUXFgYohYSqVyACMAAxNltbFsgrK6F0ArMX9QAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMIHsCu5rIN4BQyyAFAM5hxRgBcyImAtgEbQCUdFUoA5gNxFkoSFABucADZ0GLaAOJQIZCGBIdko9MAAmAgL4ECMbAjDB0IZDxUZsItXVs4o+QRJXIEWZ8gC8yYxBTc0tySmppJlYoNnw9ZDgyNG8ReU8U6AA6YWhxCT9kAEYAJgBmNK87LMVlMALA4ItSWLw9NMUwTChLSud9Q3c6hALrMCd7NgEEEkKABkmCBEyalTUp7Oc8goBWTNm+IAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYAMX0BY1dMcAoAYwBsBDRRUAYTgDsAXeC0AbxNFAAdoASwBuVFpFCIWYyKipMAngG4SAXxIlBrGADMqZCQGVIFSGWkAjU41btQkAB7imAEzo22cDt16ITZlgAKAEpUYThBFxV1cmpaUAAhAFcWFmZ7J0hXd2ZPDkEAWz5TAqyWOmNTcyorSA87H0l-cxCudRjKGjoAFUcWBLgHDOc3BlyGniaqoOC2tQ1O+IBJAqoAczrxr1BC4shS1grmy2st70mBERlJaXE5RRVfY9bOdqA
-
printLabel(myObj);
TheinterfaceLabeledValueisanamewecannowusetodescribetherequirementinthepreviousexample.Itstillrepresentshavingasinglepropertycalledlabelthatisoftypestring.Noticewedidn'thavetoexplicitlysaythattheobjectwepasstoprintLabelimplementsthisinterfacelikewemighthavetoinotherlanguages.Here,it'sonlytheshapethatmatters.Iftheobjectwepasstothefunctionmeetstherequirementslisted,thenit'sallowed.
It'sworthpointingoutthatthetypecheckerdoesnotrequirethatthesepropertiescomeinanysortoforder,onlythatthepropertiestheinterfacerequiresarepresentandhavetherequiredtype.
OptionalProperties
Notallpropertiesofaninterfacemayberequired.Someexistundercertainconditionsormaynotbethereatall.Theseoptionalpropertiesarepopularwhencreatingpatternslike"optionbags"whereyoupassanobjecttoafunctionthatonlyhasacoupleofpropertiesfilledin.
Here'sanexampleofthispattern:
interfaceSquareConfig{color?:string;width?:number;}
functioncreateSquare(config:SquareConfig):{color:string;area:numberletnewSquare={color:"white",area:100};if(config.color){newSquare.color=config.color;}if(config.width){newSquare.area=config.width*config.width;}returnnewSquare;}
letmySquare=createSquare({color:"black"});
-
Interfaceswithoptionalpropertiesarewrittensimilartootherinterfaces,witheachoptionalpropertydenotedbya?attheendofthepropertynameinthedeclaration.
Theadvantageofoptionalpropertiesisthatyoucandescribethesepossiblyavailablepropertieswhilestillalsopreventinguseofpropertiesthatarenotpartoftheinterface.Forexample,hadwemistypedthenameofthecolorpropertyincreateSquare,wewouldgetanerrormessagelettingusknow:
interfaceSquareConfig{color?:string;width?:number;}
functioncreateSquare(config:SquareConfig):{color:string;area:numberletnewSquare={color:"white",area:100};if(config.clor){
Property'clor'doesnotexistontype'SquareConfig'.Didyoumean'color'?//Error:Property'clor'doesnotexistontype'SquareConfig'newSquare.color=config.clor;
Property'clor'doesnotexistontype'SquareConfig'.Didyoumean'color'?}if(config.width){newSquare.area=config.width*config.width;}returnnewSquare;}
letmySquare=createSquare({color:"black"});
Readonlyproperties
Somepropertiesshouldonlybemodifiablewhenanobjectisfirstcreated.Youcanspecifythisbyputtingreadonlybeforethenameoftheproperty:
interfacePoint{readonlyx:number;readonlyy:number;}
YoucanconstructaPointbyassigninganobjectliteral.Aftertheassignment,x
-
andycan'tbechanged.
letp1:Point={x:10,y:20};p1.x=5;//error!
Cannotassignto'x'becauseitisaread-onlyproperty.
TypeScriptcomeswithaReadonlyArraytypethatisthesameasArraywithallmutatingmethodsremoved,soyoucanmakesureyoudon'tchangeyourarraysaftercreation:
leta:number[]=[1,2,3,4];letro:ReadonlyArray=a;
ro[0]=12;//error!
Indexsignatureintype'readonlynumber[]'onlypermitsreading.ro.push(5);//error!
Property'push'doesnotexistontype'readonlynumber[]'.ro.length=100;//error!
Cannotassignto'length'becauseitisaread-onlyproperty.a=ro;//error!
Thetype'readonlynumber[]'is'readonly'andcannotbeassignedtothemutabletype'number[]'.
OnthelastlineofthesnippetyoucanseethatevenassigningtheentireReadonlyArraybacktoanormalarrayisillegal.Youcanstilloverrideitwithatypeassertion,though:
leta:number[]=[1,2,3,4];letro:ReadonlyArray=a;
a=roasnumber[];
readonlyvsconstTheeasiestwaytorememberwhethertousereadonlyorconstistoaskwhetheryou'reusingitonavariableoraproperty.Variablesuseconstwhereaspropertiesusereadonly.
ExcessPropertyChecks
-
ExcessPropertyChecks
Inourfirstexampleusinginterfaces,TypeScriptletsuspass{size:number;label:string;}tosomethingthatonlyexpecteda{label:string;}.Wealsojustlearnedaboutoptionalproperties,andhowthey'reusefulwhendescribingso-called"optionbags".
However,combiningthetwonaivelywouldallowanerrortosneakin.Forexample,takingourlastexampleusingcreateSquare:
interfaceSquareConfig{color?:string;width?:number;}
functioncreateSquare(config:SquareConfig):{color:string;area:numberreturn{color:config.color||"red",area:config.width?config.width*config.width:20,};}
letmySquare=createSquare({colour:"red",width:100});
Argumentoftype'{colour:string;width:number;}'isnotassignabletoparameteroftype'SquareConfig'.Objectliteralmayonlyspecifyknownproperties,but'colour'doesnotexistintype'SquareConfig'.Didyoumeantowrite'color'?
NoticethegivenargumenttocreateSquareisspelledcolourinsteadofcolor.InplainJavaScript,thissortofthingfailssilently.
Youcouldarguethatthisprogramiscorrectlytyped,sincethewidthpropertiesarecompatible,there'snocolorpropertypresent,andtheextracolourpropertyisinsignificant.
However,TypeScripttakesthestancethatthere'sprobablyabuginthiscode.Objectliteralsgetspecialtreatmentandundergoexcesspropertycheckingwhenassigningthemtoothervariables,orpassingthemasarguments.Ifanobjectliteralhasanypropertiesthatthe"targettype"doesn'thave,you'llgetanerror:
letmySquare=createSquare({colour:"red",width:100});
Argumentoftype'{colour:string;width:number;}'isnotassignabletoparameteroftype'SquareConfig'.Objectliteralmayonlyspecifyknownproperties,but'colour'doesnotexistintype'SquareConfig'.Didyoumeantowrite'color'?
Gettingaroundthesechecksisactuallyreallysimple.Theeasiestmethodistojustuseatypeassertion:
-
justuseatypeassertion:
letmySquare=createSquare({width:100,opacity:0.5}asSquareConfig
However,abetterapproachmightbetoaddastringindexsignatureifyou'resurethattheobjectcanhavesomeextrapropertiesthatareusedinsomespecialway.IfSquareConfigcanhavecolorandwidthpropertieswiththeabovetypes,butcouldalsohaveanynumberofotherproperties,thenwecoulddefineitlikeso:
interfaceSquareConfig{color?:string;width?:number;[propName:string]:any;}
We'lldiscussindexsignaturesinabit,butherewe'resayingaSquareConfigcanhaveanynumberofproperties,andaslongastheyaren'tcolororwidth,theirtypesdon'tmatter.
Onefinalwaytogetaroundthesechecks,whichmightbeabitsurprising,istoassigntheobjecttoanothervariable:SincesquareOptionswon'tundergoexcesspropertychecks,thecompilerwon'tgiveyouanerror.
letsquareOptions={colour:"red",width:100};letmySquare=createSquare(squareOptions);
TheaboveworkaroundwillworkaslongasyouhaveacommonpropertybetweensquareOptionsandSquareConfig.Inthisexample,itwasthepropertywidth.Itwillhowever,failifthevariabledoesnothaveanycommonobjectproperty.Forexample:
letsquareOptions={colour:"red"};letmySquare=createSquare(squareOptions);
Type'{colour:string;}'hasnopropertiesincommonwithtype'SquareConfig'.
Keepinmindthatforsimplecodelikeabove,youprobablyshouldn'tbetryingto"getaround"thesechecks.Formorecomplexobjectliteralsthathavemethodsandholdstate,youmightneedtokeepthesetechniquesinmind,butamajorityofexcesspropertyerrorsareactuallybugs.Thatmeansifyou'rerunningintoexcesspropertycheckingproblemsforsomethinglikeoptionbags,youmight
-
needtorevisesomeofyourtypedeclarations.Inthisinstance,ifit'sokaytopassanobjectwithbothacolororcolourpropertytocreateSquare,youshouldfixupthedefinitionofSquareConfigtoreflectthat.
FunctionTypes
InterfacesarecapableofdescribingthewiderangeofshapesthatJavaScriptobjectscantake.Inadditiontodescribinganobjectwithproperties,interfacesarealsocapableofdescribingfunctiontypes.
Todescribeafunctiontypewithaninterface,wegivetheinterfaceacallsignature.Thisislikeafunctiondeclarationwithonlytheparameterlistandreturntypegiven.Eachparameterintheparameterlistrequiresbothnameandtype.
interfaceSearchFunc{(source:string,subString:string):boolean;}
Oncedefined,wecanusethisfunctiontypeinterfacelikewewouldotherinterfaces.Here,weshowhowyoucancreateavariableofafunctiontypeandassignitafunctionvalueofthesametype.
letmySearch:SearchFunc;
mySearch=function(source:string,subString:string):boolean{letresult=source.search(subString);returnresult>-1;};
Forfunctiontypestocorrectlytypecheck,thenamesoftheparametersdonotneedtomatch.Wecouldhave,forexample,writtentheaboveexamplelikethis:
letmySearch:SearchFunc;
mySearch=function(src:string,sub:string):boolean{letresult=src.search(sub);returnresult>-1;};
-
Functionparametersarecheckedoneatatime,withthetypeineachcorrespondingparameterpositioncheckedagainsteachother.Ifyoudonotwanttospecifytypesatall,TypeScript'scontextualtypingcaninfertheargumenttypessincethefunctionvalueisassigneddirectlytoavariableoftypeSearchFunc.Here,also,thereturntypeofourfunctionexpressionisimpliedbythevaluesitreturns(herefalseandtrue).
letmySearch:SearchFunc;
mySearch=function(src,sub){letresult=src.search(sub);returnresult>-1;};
Hadthefunctionexpressionreturnednumbersorstrings,thetypecheckerwouldhavemadeanerrorthatindicatesreturntypedoesn'tmatchthereturntypedescribedintheSearchFuncinterface.
letmySearch:SearchFunc;
mySearch=function(src,sub){
Type'(src:string,sub:string)=>string'isnotassignabletotype'SearchFunc'.Type'string'isnotassignabletotype'boolean'.letresult=src.search(sub);return"string";};
IndexableTypes
Similarlytohowwecanuseinterfacestodescribefunctiontypes,wecanalsodescribetypesthatwecan"indexinto"likea[10],orageMap["daniel"].Indexabletypeshaveanindexsignaturethatdescribesthetypeswecanusetoindexintotheobject,alongwiththecorrespondingreturntypeswhenindexing.Let'stakeanexample:
interfaceStringArray{[index:number]:string;}
letmyArray:StringArray;
-
myArray=["Bob","Fred"];
letmyStr:string=myArray[0];
Above,wehaveaStringArrayinterfacethathasanindexsignature.ThisindexsignaturestatesthatwhenaStringArrayisindexedwithanumber,itwillreturnastring.
Therearetwotypesofsupportedindexsignatures:stringandnumber.Itispossibletosupportbothtypesofindexers,butthetypereturnedfromanumericindexermustbeasubtypeofthetypereturnedfromthestringindexer.Thisisbecausewhenindexingwithanumber,JavaScriptwillactuallyconvertthattoastringbeforeindexingintoanobject.Thatmeansthatindexingwith100(anumber)isthesamethingasindexingwith"100"(astring),sothetwoneedtobeconsistent.
interfaceAnimal{name:string;}
interfaceDogextendsAnimal{breed:string;}
//Error:indexingwithanumericstringmightgetyouacompletelyseparatetypeofAnimal!interfaceNotOkay{[x:number]:Animal;
Numericindextype'Animal'isnotassignabletostringindextype'Dog'.[x:string]:Dog;}
Whilestringindexsignaturesareapowerfulwaytodescribethe"dictionary"pattern,theyalsoenforcethatallpropertiesmatchtheirreturntype.Thisisbecauseastringindexdeclaresthatobj.propertyisalsoavailableasobj["property"].Inthefollowingexample,name'stypedoesnotmatchthestringindex'stype,andthetypecheckergivesanerror:
interfaceNumberDictionary{[index:string]:number;length:number;//ok,lengthisanumbername:string;//error,thetypeof'name'isnotasubtypeoftheindexer
Property'name'oftype'string'isnotassignabletostringindextype'number'.}
-
However,propertiesofdifferenttypesareacceptableiftheindexsignatureisaunionofthepropertytypes:
interfaceNumberOrStringDictionary{[index:string]:number|string;length:number;//ok,lengthisanumbername:string;//ok,nameisastring}
Finally,youcanmakeindexsignaturesreadonlyinordertopreventassignmenttotheirindices:
interfaceReadonlyStringArray{readonly[index:number]:string;}
letmyArray:ReadonlyStringArray=["Alice","Bob"];myArray[2]="Mallory";//error!
Indexsignatureintype'ReadonlyStringArray'onlypermitsreading.
Youcan'tsetmyArray[2]becausetheindexsignatureisreadonly.
ClassTypes
ImplementinganinterfaceOneofthemostcommonusesofinterfacesinlanguageslikeC#andJava,thatofexplicitlyenforcingthataclassmeetsaparticularcontract,isalsopossibleinTypeScript.
interfaceClockInterface{currentTime:Date;}
classClockimplementsClockInterface{currentTime:Date=newDate();constructor(h:number,m:number){}}
-
Youcanalsodescribemethodsinaninterfacethatareimplementedintheclass,aswedowithsetTimeinthebelowexample:
interfaceClockInterface{currentTime:Date;setTime(d:Date):void;}
classClockimplementsClockInterface{currentTime:Date=newDate();setTime(d:Date){this.currentTime=d;}constructor(h:number,m:number){}}
Interfacesdescribethepublicsideoftheclass,ratherthanboththepublicandprivateside.Thisprohibitsyoufromusingthemtocheckthataclassalsohasparticulartypesfortheprivatesideoftheclassinstance.
DifferencebetweenthestaticandinstancesidesofclassesWhenworkingwithclassesandinterfaces,ithelpstokeepinmindthataclasshastwotypes:thetypeofthestaticsideandthetypeoftheinstanceside.Youmaynoticethatifyoucreateaninterfacewithaconstructsignatureandtrytocreateaclassthatimplementsthisinterfaceyougetanerror:
interfaceClockConstructor{new(hour:number,minute:number);}
classClockimplementsClockConstructor{
Class'Clock'incorrectlyimplementsinterface'ClockConstructor'.Type'Clock'providesnomatchforthesignature'new(hour:number,minute:number):any'.currentTime:Date;constructor(h:number,m:number){}}
Thisisbecausewhenaclassimplementsaninterface,onlytheinstancesideoftheclassischecked.Sincetheconstructorsitsinthestaticside,itisnotincludedinthischeck.
-
Instead,youwouldneedtoworkwiththestaticsideoftheclassdirectly.Inthisexample,wedefinetwointerfaces,ClockConstructorfortheconstructorandClockInterfacefortheinstancemethods.Then,forconvenience,wedefineaconstructorfunctioncreateClockthatcreatesinstancesofthetypethatispassedtoit:
interfaceClockConstructor{new(hour:number,minute:number):ClockInterface;}
interfaceClockInterface{tick():void;}
functioncreateClock(ctor:ClockConstructor,hour:number,minute:number):ClockInterface{returnnewctor(hour,minute);}
classDigitalClockimplementsClockInterface{constructor(h:number,m:number){}tick(){console.log("beepbeep");}}
classAnalogClockimplementsClockInterface{constructor(h:number,m:number){}tick(){console.log("ticktock");}}
letdigital=createClock(DigitalClock,12,17);letanalog=createClock(AnalogClock,7,32);
BecausecreateClock'sfirstparameterisoftypeClockConstructor,increateClock(AnalogClock,7,32),itchecksthatAnalogClockhasthecorrectconstructorsignature.
Anothersimplewayistouseclassexpressions:
interfaceClockConstructor{
-
new(hour:number,minute:number):ClockInterface;}
interfaceClockInterface{tick():void;}
constClock:ClockConstructor=classClockimplementsClockInterface{constructor(h:number,m:number){}tick(){console.log("beepbeep");}};
letclock=newClock(12,17);clock.tick();
ExtendingInterfaces
Likeclasses,interfacescanextendeachother.Thisallowsyoutocopythemembersofoneinterfaceintoanother,whichgivesyoumoreflexibilityinhowyouseparateyourinterfacesintoreusablecomponents.
interfaceShape{color:string;}
interfaceSquareextendsShape{sideLength:number;}
letsquare={}asSquare;square.color="blue";square.sideLength=10;
Aninterfacecanextendmultipleinterfaces,creatingacombinationofalloftheinterfaces.
interfaceShape{color:string;}
interfacePenStroke{penWidth:number;
-
}
interfaceSquareextendsShape,PenStroke{sideLength:number;}
letsquare={}asSquare;square.color="blue";square.sideLength=10;square.penWidth=5.0;
HybridTypes
Aswementionedearlier,interfacescandescribetherichtypespresentinrealworldJavaScript.BecauseofJavaScript'sdynamicandflexiblenature,youmayoccasionallyencounteranobjectthatworksasacombinationofsomeofthetypesdescribedabove.
Onesuchexampleisanobjectthatactsasbothafunctionandanobject,withadditionalproperties:
interfaceCounter{(start:number):string;interval:number;reset():void;}
functiongetCounter():Counter{letcounter=function(start:number){}asCounter;counter.interval=123;counter.reset=function(){};returncounter;}
letc=getCounter();c(10);c.reset();c.interval=5.0;
Wheninteractingwith3rd-partyJavaScript,youmayneedtousepatternsliketheabovetofullydescribetheshapeofthetype.
-
InterfacesExtendingClasses
Whenaninterfacetypeextendsaclasstypeitinheritsthemembersoftheclassbutnottheirimplementations.Itisasiftheinterfacehaddeclaredallofthemembersoftheclasswithoutprovidinganimplementation.Interfacesinheriteventheprivateandprotectedmembersofabaseclass.Thismeansthatwhenyoucreateaninterfacethatextendsaclasswithprivateorprotectedmembers,thatinterfacetypecanonlybeimplementedbythatclassorasubclassofit.
Thisisusefulwhenyouhavealargeinheritancehierarchy,butwanttospecifythatyourcodeworkswithonlysubclassesthathavecertainproperties.Thesubclassesdon'thavetoberelatedbesidesinheritingfromthebaseclass.Forexample:
classControl{privatestate:any;}
interfaceSelectableControlextendsControl{select():void;}
classButtonextendsControlimplementsSelectableControl{select(){}}
classTextBoxextendsControl{select(){}}
classImageControlimplementsSelectableControl{
Class'ImageControl'incorrectlyimplementsinterface'SelectableControl'.Typeshaveseparatedeclarationsofaprivateproperty'state'.privatestate:any;select(){}}
Intheaboveexample,SelectableControlcontainsallofthemembersofControl,includingtheprivatestateproperty.SincestateisaprivatememberitisonlypossiblefordescendantsofControltoimplementSelectableControl.ThisisbecauseonlydescendantsofControlwillhaveastateprivatememberthatoriginatesinthesamedeclaration,whichisarequirementforprivatememberstobecompatible.
-
WithintheControlclassitispossibletoaccessthestateprivatememberthroughaninstanceofSelectableControl.Effectively,aSelectableControlactslikeaControlthatisknowntohaveaselectmethod.TheButtonandTextBoxclassesaresubtypesofSelectableControl(becausetheybothinheritfromControlandhaveaselectmethod).TheImageControlclasshasit'sownstateprivatememberratherthanextendingControl,soitcannotimplementSelectableControl.
-
FunctionsFunctionsarethefundamentalbuildingblockofanyapplicationinJavaScript.They'rehowyoubuilduplayersofabstraction,mimickingclasses,informationhiding,andmodules.InTypeScript,whilethereareclasses,namespaces,andmodules,functionsstillplaythekeyroleindescribinghowtodothings.TypeScriptalsoaddssomenewcapabilitiestothestandardJavaScriptfunctionstomakethemeasiertoworkwith.
Functions
Tobegin,justasinJavaScript,TypeScriptfunctionscanbecreatedbothasanamedfunctionorasananonymousfunction.Thisallowsyoutochoosethemostappropriateapproachforyourapplication,whetheryou'rebuildingalistoffunctionsinanAPIoraone-offfunctiontohandofftoanotherfunction.
ToquicklyrecapwhatthesetwoapproacheslooklikeinJavaScript:
//Namedfunctionfunctionadd(x,y){returnx+y;}
//AnonymousfunctionletmyAdd=function(x,y){returnx+y;};
JustasinJavaScript,functionscanrefertovariablesoutsideofthefunctionbody.Whentheydoso,they'resaidtocapturethesevariables.Whileunderstandinghowthisworks(andthetrade-offswhenusingthistechnique)isoutsideofthescopeofthisarticle,havingafirmunderstandinghowthismechanicworksisanimportantpieceofworkingwithJavaScriptandTypeScript.
letz=100;
https://www.typescriptlang.org/play/#code/PTAEAEGcBcCcEsDG0BcoBmBDANpApgFAigBymAtngCYYCuAdsvAPb0HoNOuiZVUAUADwA0oAJ4BKUAG8CoULDzRaseqEGgA1OIDcBAL4EiYAIL1WY8s1qQ6jaCzbYlocmJN9QAXjtc1Q0UkZOQUlFTUNbTE9fR0gAhttps://www.typescriptlang.org/play/#code/PTAEAEGcBcCcEsDG0BcoBmBDANpApgFDZ7SgBeoAvKAIwAMdA3AQegK4B2y8A9h6JgAmggCo8AWgAoAHgBpQATwCUoAN4FQoWCTax+00AGpFR8swC+QAhttps://www.typescriptlang.org/play/#code/GYVwdgxgLglg9mABAQwCaoBQA8BciwgC2ARgKYBOANIgJ54EkUCU9RZ5iA3gFCKLmkoIckiyIA1LQDc3AL7duAG0GJCNAILpEAXkShIsBImytGVWqfYt8bCl179Bw0ROlypQAhttps://www.typescriptlang.org/play/#code/DYUwLgBAtgngggEwQLggCgB6oHYFcoBGIATgDQQw75HECUEAvAHwR6EmMQBmu2AxmACWAe2zoAUBAhZW1EqUkUq7YuNrKaEAN6Li4XMTEYIAagoBucQF9zQAhttps://www.typescriptlang.org/play/#code/DYUwLgBAtgngggEwQLggCgEYEMDOIBqWwAriKgHbFQYgBOANBAJbkDGtIUI5YFVNtAJQQAvAD4IlanVEQAZsTZgmAe3LoAUBAgAPPtIZaIMfQI2DTMgN5GOYYrXU6IAamMBuDQF93QAhttps://www.typescriptlang.org/play/#code/PTAEBUAsFNQBwIYCcEFtoBdpIM6gOQAe+oCAdgCYECeJkCAbrBjKBtXLGQK6oBG2AFAAbTKFTUAghSoBeUADNuZAMYYAlgHsyoABSEAXKB79sAGlDUjJgUgCU13rdABvQaFBJM3JDsKgAaksAbkEAX1DBEHEpGVB6PBZYJWFhRWU1LR12ThExCWkKACYjXT4EHGgANQRhbmhHUyQLdVUvdDIMRts7UFkAPmMnbD701Q1tPUILal63Dy8MHz9AkPDgoAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwFYMBYBQAzAVwDsBjAFwEs5jQAjQygGwBMA5AQwFtIAKfSknKceqROWiViAcwA0oJh3EjIYiVOkBKUAG9coUNEjlC0WgKErQAalAAiezYVLh3SAG5cAX1y4mxw0hEQiZyAEZQAF56RlYVXjsAITg6O013UBBQGHhoeXI4OFB8SAB3UAAHDmg3chhEPwCjYNC0KJjmdjcE5NT5OwBBFm5EO36AZWgAOjSMrJyEfMLQLg5iAE9K6tr6xvJAlvIAZnaGTviklLH7IZHZzLAOAAt5ACtCcUNKaSfyIAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwFYMBYBQAzAVwDsBjAFwEs5jQAjQygGwBMA5AQwFtIAKfSknKceqROWiViAcwA0oJh3EjIAfjESp0gJSgA3rlChK+UL0XLukXdEjlC0WgKErQAalAAiL+4VLhVgDchqCQTIiQoLb2jqDOljzBAL64uEx2UZCIhEzkAIygALz0jKwqvJ4AQnB0ntqBoCCgAO4IANaIoKQIthRMAJ6gxHDNaRm22bloRSXM7FYV1bXyngCCLNyInisAytAAdHUNTTDw0PLkcHCgXBzEgwAOHNBW5DCIY+SZk+QAzDMMOblKo1bZedabI6NMAcAAW8gAVoRxFFKNJYeQgAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwFYMBYBQAzAVwDsBjAFwEs5jQAjQygGwBMA5AQwFtIAKfSknKceqROWiViAcwA0oJh3EjIoALygARAGUulcgAtNASlABvXKFDRI5QtFoChK0AGotH94uXdIAblwAX1xcJltrSERCJnIARnV6RlYVXk0AITg6Ez9QEFAAdwQAa0RQUgQbCiYAT1BiOHz5GzsHUvTM0F19I1DwmyiYtASGZnZfVIys+RIWSAFiSBZjHLzxZiYC4sR5DiZEOAiW4jbJzr1DTV7yCIHyAGZhpLGeCczNeU0AQRZuRHetbTQAB02VyYBg8Gg8nIcAOXA4xFqAAcONBfOQYIgrjdouRsI9Ril2lMtN9fqC8hwDPIAFaEcTWSjSAzkIAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwFYMBYBQAzAVwDsBjAFwEs5jQAjQygGwBMA5AQwFtIAKfSknKceoALygARAHVmTSQBpQTDomHdIqNdErEA5gEpQAb1yhQ0SOULRaAoSMigA1FLeuVaxwG5cAX1xcJisLSERCJnIARnF6RlZHXkkAITg6SQNvUBBQGHhoJXI4OFB8SAB3UAAHDmgNchhEIJDLcMi0WIZmdg0k1PSlSQBBFm5ERSkAZWgAOgysnLyEQuLQLg5iAE9q2vrG5vJQtvIAZk74np4+tInh0a5xzOywOABrDm2NllDrW0QpfqgEZjSQHI4RcjYc7dRIkFiQATESAsQbAh7zZ6gN4fUBfH42Yj-GRyIH3cZAAhttps://www.typescriptlang.org/play/#code/GYVwdgxgLglg9mABAIxDANgEwHIEMC2ApgBTAwBOAzlHkQFyLXkxgDmANIgHQ-mHUB5YLUIMmLVgG0AugEpEAbwBQiRHyghySMlRoFCiANSIARKaNr+UISK4ArOC2JmTsgNxKAvkqUB6X4iE+AAO6HAAnoSEIogA7hjoKAYmAFJwlITBABaIAMoEIISJADIgELiUiACyuBAA0iwAXjCEJkrohFCBIWGR0fqIALwoaFgizmkZ2SacJvn4hegzpqXllMsmNfVNLa5uQAhttps://www.typescriptlang.org/play/#code/GYVwdgxgLglg9mABAIxDANgEwHIEMC2ApgBTAwBOAzlHkQFyLXkxgDmANIgHQ-mHUB5YLUIMmLVgG0AugEpEAbwBQiRHyghySMlRoFCiANSIARKaNr+UISK4ArOC2JmTsgNxKAvkqXpCUFDQsEQAxcAZSMH0xKGY2Th4uPmoYuKk5RABeAD5GWIkswIwcfTcgAhttps://www.typescriptlang.org/play/#code/PTAEAEGcBcCcEsDG0BcoBmBDANpApgFDZ7SgAmeiA1qALygDeBookArvNJGgNoBEACzyZYXPgBpQfSAAdMFSBKmJsbAEaLJfMvEwBbAPYA7MooC645qEQjTaAIKxYmAJ4AKAKwAmAJSWWiLDC0HgAwrYACkhUeLBo6GxGyPDGoG4+jFYsQdBssEYYicmp6Zks5aDEpDLReGThsGR0oACymNACAHTo2AYGsG5tHZ3OJgZ6pQBUoN4+ANxZ5VWgNdR1AMocpPRDXT19A6sx9bagYACMAMzzBIvZJHkFDKxbaB3wkJ3snJA8RxtbCzWWxof4nRqgACkoCuoAAvgsKgirHDLMiiCRgY0omtYM0KNROoFgmFIrUBjdlmCGk16DZseT0gsCDhYtA3Hx6WQ0HxQABqFa1cFkImnAW8gzoKT8wVrYVfLbzIAhttps://www.typescriptlang.org/play/#code/PTAEAEGcBcCcEsDG0BcoBmBDANpApgFDZ7SgAmeiA1qALygDeBookArvNJGgNoBEACzyZYXPgBpQfSAAdMFSBKmJsbAEaLJfMvEwBbAPYA7MooC645qEQjTaAIKxYmAJ4AKAKwAmAJSWWiLDC0HgAwrYACkhUeLBo6GxGyPDGoG4+jFYsIKAAcgDyACoAomjQQqDY8EZ4oGp42AYA7qDwkKBGzaCYRt1OXQlJ0ClGkjiNTdUA5qBs7dAG1pgy0GxBoADk5W0boAhTAqRCQVl7JGu96XQAfJks95UkoDLReGThsGR0oACymOUAOnQjQMsDcf0BzhMBj0VwAVKBvD4ANynFjEUgvahvADKHFI9AhAiBILBWJi71soDAAEYAMwoghos6rWC9BisfFlARtAHsTiQHjk3H4ixLT5oYWUz6gACkoHpoAAvqiHiqrErLOqiE8bJ8otjYN8KNQAYFgmFIq8wYyMc9XtKvvQ9WQDTEbaiCDhYtA3HwXWg+KAANT27GOs1U0NBgzoKQhsMUj5kPn4lFAAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgMJygE2QbwFDLIDOArsGAFzFhSgDmA3AcghplSCQLYBG0TAXzx5QkWIhQARCAgDWuZqXJEqRGvQDaAXSaFWWFck69o23SygQ4kdFgAKwOdAAUYABbBD0uQEoqzn2QAXgA+NDZBYQAbCDBkTBlZKm95IIVCJTBDDQAiNysoLJyAGmQcogAHOASiErKEKJIeWtKczGA4LgB7EExarWLmfT6qAEEoKDgAT2cAVgAmH0HCAHoV5AA5AHkAFQBRKh385BgSEAQwYB6jLoB3ZAgADwqox3IoqeIKmWAYYAgiMh3NZkMoWHAojEUFwSGpkHxkF0YECpt9kCkhpZrBBbJgHE4oFRTudLtdXB4vIlAvhCIRLGASFAQMgAsEwjTaYQYnEKo5ZBBMLjgsgALLWNwAOhgUS6XSgzjF7glk16XS4rIAVMgFj5zJzucheU5MABlMhxNKKyXS2Xyo38wVsZDrACMAGZdcJOXTYozmThiOaqO5PBLMkQNPaBWbyANwVgqFHHVhkABSZDu5ACPVZ8wCQbZ6KxeN4vnQYUJOQShBYmxsfH8+Weg1JoVpYYNlyevAQ6BgZw5YZUHLIADUhrLycw1ad45HSLKY4nxtxYfNuqAAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgKoEkCiAbCBbCcZAbwChlk4ATKgYW2AQGsAZYAZ0hGgAoB7EAgbMAXMh5gAFhzEA3PsCoAaZBDGZZhMAEpkAXgB8yeYu1yFVANykAvkAhttps://www.typescriptlang.org/play/#code/PTAEAEGcBcCcEsDG0BcoBmBDANpApgFAgR6ywD2skaATAMwAsArAfAHbSlaJ6gCqASQCi2PAFs8HUAG8CoUJgAmigMLYkAawAy8GJNIAKcm0TrEGtAegALXWgBu5eIoA0oPGiH3J0AJSgAXgA+UEdnXwcnRQBuAgBfVg4uTB5QLx8ZOVAJSEhMAHMPUBgENnzYhMU8U0xYXkRjGFAAV3gRcR80QXaJDljiAFohxGboIYGCGtzQAAlMNkVRWEz5dnRyNBL2cqzjNU0AISUrW2pZ+cXSNyL0jn9ZeXlicnIAB0g3ZvxFUAADG10v1A1lIeAAdC1INtQADIKBEDhsAAjFIaUAAd3IzWwP0QsEwkGsCmgoFgzQ48AkWXksLBa3IgXcYJyeUKsXkCQSBFEJKJAVAbDw6POCyWBl8sVaPR8YKUqjM2l0nEFsAM1jBewVR0UEtAxFIFFgAEIgAhttps://www.typescriptlang.org/play/#code/PTAEAEGcBcCcEsDG0BcoBmBDANpApgFDwB20esWieoAqgJICi2eAtnqaAN4GiiYAm-AMLYkAawAy8GO3IAKAPbFEoxGLRzoAC2loAbgvj8ANKDxoGe9tACUoALwA+UAaM39h-gG4CAXyKk5JTUltZcPKBskJCYAObmoDAIxLE+-vx4Kpiw1IhKMKAArvBMrNZo9KVspD4goAC0jYiF0I31BFnRoAASmMT8zLDhvCToCmhJJKkRSiLiAOIKCvyaOpAeRqYJoaR23Ly8dYh9AOTQRfigAAba0legWuTUAEaZmIWX8NAnkKAK6KBoABPAAO1Fc-AAhBFeHliJAFMwAHTYBSxOQAIhU4jwUIxNh8vH8-gIzHOWgcoGIeAA7j0+gN5ASCMUqtYkQJhKpJNIyNTYHItEjZtzFssCUAhttps://www.typescriptlang.org/play/#code/PTAEAEGcBcCcEsDG0BcoBmBDANpApgFDwB20esWieoAqgJICi2eAtnqaAN4GiiYAm-AMLYkAawAy8GO3IAKAPbFEoxGLRzoAC2loAbgvj8ANKDxoGe9tACUoALwA+UAaM39h-gG4CAXyKk5JTUltZcPKBskJCYAObmoDAIxLE+-vx4Kpiw1IhKMKAArvBMrNZo9KVspD4goAC0jYiF0I31BFnRoAASmMT8zLDhvCToCmhJJKkRSiLiAOIKCvwOoHIJoaR2TsO8oNrSAHSjCqt4h1Ex8T68vmlAAhttps://www.typescriptlang.org/play/#code/PTAEAEGcBcCcEsDG0BcoBmBDANpApgFDZ7SiQCu80koAvKANoBEAFnprNUwDShOQAHTABM8kHn0TZyAI3G8mw+JgC2AewB2w8QF0A3AQLpyG5PE2gBSANYBhDsIAUADzSYNATwCUbz6ADeBKCgIKC2bIjWoNBqZHh4oPDooADueADksAkparDW8BoA5qlULKDuoGoyAFZ4yMAcsJgeQSFgSWRqvNBsHqCFmABuCeQ0PQmikeVaqRnY2JY20WygiA6tHY7QHgJ4asnOdPRMVbXITF4BrcHEpFaReML2sMJ0oACymD0AdOjYarlHJ8fk0tGoVI5LgAqUDOb7EIo9LwGYLBLLQciwDSLB5PBwo0AAX1aoQA8uNYCl4PhQNVRqRbss8CocVFxqt1sE8LgEpttrt9rCjnwNOQVDI8LALldUaBGfdrI8AMqUUj0YEsX7-QGHMAARgAzMjrqB0Zjsf4yKq0BQqJAGArlaqdLw1i80IcAKSgQ1EgnE4lEEigFQeAAidSi9AYrUtttQfCUqk02gkbuEaAATETuLGrVQ0PwhKJ5Bz3T6AAw5vPxwtsDhcV0ONAAFmr+kM8psj2ewj1b1DEciDpsvccg8jXg7OEl0EcTHThdAAGpWT2HHrvumV3xKskmDvHXiXpv48ag3du8fhNn6Aqx3qAKzGmeceeL3ero+9zNbhw7g9BQPL8rx-b4zz0IAhttps://www.typescriptlang.org/play/#code/DYUwLgBAzgrglmKEC8EDaAiAFiAhgJ0QwBoIMoAHXAExChLIGNgYAje0jauXAWwHsAdtXoBdANwAoSQDMYgxmDhCIFOIwDWAYQLUAFAA8AXBADe0eGBNQw+OIIDm4iI10nBMXqxD4IAXzRRAEp3T298KTkFJRU1TR18fWMIDy8fELMLBGtbeycXNxSwn39I+UVlQVV1bV1DE1xBAE8MxqazSQgIAHpuiC0cTQgwfmgQEAg4GQgAdxAAcnwJmf58DTzZhCwIRoh+VgArEEVugnxcJs6evqnoflIwHHaHXAA3CZgkR4naIcbqWYLYDAapDb4FRJXW56MBNCggfjTAwoVAYfZHRQYIIdLpdUCQOIaEDUBIA1AAWVwjwAdDJgPxVnpKTTzsJ+Lw9NiAFQQAzU0COR5BKS4iBLMAwfBVQnE0ki-xXXoQADy33wMzgUAmB0+kHxwxwvFBGgNE1ckK6IGAWsm0xhcIRSJRZFS4SxONx+pl1AAypYUBBmVhafTGci+gBGADMwquXXFkqq5lg2SyiDQ3r9CFEpHN1BMyIApBBo6Urn5JBXJPreE0ACLHE2oNBXZOWExcHgCYQcCH5iAAJn8xFbaY7lBodAYeZMEYADMPRymrGQcAQiLnCgAWRcSaRemqy3QRgO1huaDM1Ul6M+NoJ73CgQh6DAzsgQADUxqPiQj1Lzn7voi75ft6pJ-susbVuA34kroQ6oIS14RgArLGj4+GAL5vhggFgfB-66IBuHAbhoGHnBiQDtSkHiEAA
-
functionaddToZ(x,y){returnx+y+z;}
FunctionTypes
Typingthefunction
Let'saddtypestooursimpleexamplesfromearlier:
functionadd(x:number,y:number):number{returnx+y;}
letmyAdd=function(x:number,y:number):number{returnx+y;};
Wecanaddtypestoeachoftheparametersandthentothefunctionitselftoaddareturntype.TypeScriptcanfigurethereturntypeoutbylookingatthereturnstatements,sowecanalsooptionallyleavethisoffinmanycases.
Writingthefunctiontype
Nowthatwe'vetypedthefunction,let'swritethefulltypeofthefunctionoutbylookingateachpieceofthefunctiontype.
letmyAdd:(x:number,y:number)=>number=function(x:number,y:number):number{returnx+y;};
Afunction'stypehasthesametwoparts:thetypeoftheargumentsandthereturntype.Whenwritingoutthewholefunctiontype,bothpartsarerequired.
-
returntype.Whenwritingoutthewholefunctiontype,bothpartsarerequired.Wewriteouttheparametertypesjustlikeaparameterlist,givingeachparameteranameandatype.Thisnameisjusttohelpwithreadability.Wecouldhaveinsteadwritten:
letmyAdd:(baseValue:number,increment:number)=>number=function(x:number,y:number):number{returnx+y;};
Aslongastheparametertypeslineup,it'sconsideredavalidtypeforthefunction,regardlessofthenamesyougivetheparametersinthefunctiontype.
Thesecondpartisthereturntype.Wemakeitclearwhichisthereturntypebyusinganarrow(=>)betweentheparametersandthereturntype.Asmentionedbefore,thisisarequiredpartofthefunctiontype,soifthefunctiondoesn'treturnavalue,youwouldusevoidinsteadofleavingitoff.
Ofnote,onlytheparametersandthereturntypemakeupthefunctiontype.Capturedvariablesarenotreflectedinthetype.Ineffect,capturedvariablesarepartofthe"hiddenstate"ofanyfunctionanddonotmakeupitsAPI.
Inferringthetypes
Inplayingwiththeexample,youmaynoticethattheTypeScriptcompilercanfigureoutthetypeevenifyouonlyhavetypesononesideoftheequation:
//Theparameters'x'and'y'havethetypenumberletmyAdd=function(x:number,y:number):number{returnx+y;};
//myAddhasthefullfunctiontypeletmyAdd2:(baseValue:number,increment:number)=>number=functionreturnx+y;};
Thisiscalled"contextualtyping",aformoftypeinference.Thishelpscutdownontheamountofefforttokeepyourprogramtyped.
-
ontheamountofefforttokeepyourprogramtyped.
OptionalandDefaultParameters
InTypeScript,everyparameterisassumedtoberequiredbythefunction.Thisdoesn'tmeanthatitcan'tbegivennullorundefined,butrather,whenthefunctioniscalled,thecompilerwillcheckthattheuserhasprovidedavalueforeachparameter.Thecompileralsoassumesthattheseparametersaretheonlyparametersthatwillbepassedtothefunction.Inshort,thenumberofargumentsgiventoafunctionhastomatchthenumberofparametersthefunctionexpects.
functionbuildName(firstName:string,lastName:string){returnfirstName+""+lastName;}
letresult1=buildName("Bob");//error,toofewparameters
Expected2arguments,butgot1.letresult2=buildName("Bob","Adams","Sr.");//error,toomanyparameters
Expected2arguments,butgot3.letresult3=buildName("Bob","Adams");//ah,justright
InJavaScript,everyparameterisoptional,andusersmayleavethemoffastheyseefit.Whentheydo,theirvalueisundefined.WecangetthisfunctionalityinTypeScriptbyaddinga?totheendofparameterswewanttobeoptional.Forexample,let'ssaywewantthelastnameparameterfromabovetobeoptional:
functionbuildName(firstName:string,lastName?:string){if(lastName)returnfirstName+""+lastName;elsereturnfirstName;}
letresult1=buildName("Bob");//workscorrectlynowletresult2=buildName("Bob","Adams","Sr.");//error,toomanyparameters
Expected1-2arguments,butgot3.letresult3=buildName("Bob","Adams");//ah,justright
Anyoptionalparametersmustfollowrequiredparameters.Hadwewantedtomakethefirstnameoptional,ratherthanthelastname,wewouldneedtochangetheorderofparametersinthefunction,puttingthefirstnamelastinthelist.
-
InTypeScript,wecanalsosetavaluethataparameterwillbeassignediftheuserdoesnotprovideone,oriftheuserpassesundefinedinitsplace.Thesearecalleddefault-initializedparameters.Let'stakethepreviousexampleanddefaultthelastnameto"Smith".
functionbuildName(firstName:string,lastName="Smith"){returnfirstName+""+lastName;}
letresult1=buildName("Bob");//workscorrectlynow,returns"BobSmith"letresult2=buildName("Bob",undefined);//stillworks,alsoreturns"BobSmith"letresult3=buildName("Bob","Adams","Sr.");//error,toomanyparameters
Expected1-2arguments,butgot3.letresult4=buildName("Bob","Adams");//ah,justright
Default-initializedparametersthatcomeafterallrequiredparametersaretreatedasoptional,andjustlikeoptionalparameters,canbeomittedwhencallingtheirrespectivefunction.Thismeansoptionalparametersandtrailingdefaultparameterswillsharecommonalityintheirtypes,soboth
functionbuildName(firstName:string,lastName?:string){//...}
and
functionbuildName(firstName:string,lastName="Smith"){//...}
sharethesametype(firstName:string,lastName?:string)=>string.ThedefaultvalueoflastNamedisappearsinthetype,onlyleavingbehindthefactthattheparameterisoptional.
Unlikeplainoptionalparameters,default-initializedparametersdon'tneedtooccurafterrequiredparameters.Ifadefault-initializedparametercomesbeforearequiredparameter,usersneedtoexplicitlypassundefinedtogetthedefaultinitializedvalue.Forexample,wecouldwriteourlastexamplewithonlyadefaultinitializeronfirstName:
functionbuildName(firstName="Will",lastName:string){returnfirstName+""+lastName;}
-
letresult1=buildName("Bob");//error,toofewparameters
Expected2arguments,butgot1.letresult2=buildName("Bob","Adams","Sr.");//error,toomanyparameters
Expected2arguments,butgot3.letresult3=buildName("Bob","Adams");//okayandreturns"BobAdams"letresult4=buildName(undefined,"Adams");//okayandreturns"WillAdams"
RestParameters
Required,optional,anddefaultparametersallhaveonethingincommon:theytalkaboutoneparameteratatime.Sometimes,youwanttoworkwithmultipleparametersasagroup,oryoumaynotknowhowmanyparametersafunctionwillultimatelytake.InJavaScript,youcanworkwiththeargumentsdirectlyusingtheargumentsvariablethatisvisibleinsideeveryfunctionbody.
InTypeScript,youcangathertheseargumentstogetherintoavariable:
functionbuildName(firstName:string,...restOfName:string[]){returnfirstName+""+restOfName.join("");}
//employeeNamewillbe"JosephSamuelLucasMacKinzie"letemployeeName=buildName("Joseph","Samuel","Lucas","MacKinzie");
Restparametersaretreatedasaboundlessnumberofoptionalparameters.Whenpassingargumentsforarestparameter,youcanuseasmanyasyouwant;youcanevenpassnone.Thecompilerwillbuildanarrayoftheargumentspassedinwiththenamegivenaftertheellipsis(...),allowingyoutouseitinyourfunction.
Theellipsisisalsousedinthetypeofthefunctionwithrestparameters:
functionbuildName(firstName:string,...restOfName:string[]){returnfirstName+""+restOfName.join("");}
letbuildNameFun:(fname:string,...rest:string[])=>string=buildName
-
this
LearninghowtousethisinJavaScriptissomethingofariteofpassage.SinceTypeScriptisasupersetofJavaScript,TypeScriptdevelopersalsoneedtolearnhowtousethisandhowtospotwhenit'snotbeingusedcorrectly.Fortunately,TypeScriptletsyoucatchincorrectusesofthiswithacoupleoftechniques.IfyouneedtolearnhowthisworksinJavaScript,though,firstreadYehudaKatz'sUnderstandingJavaScriptFunctionInvocationand"this".Yehuda'sarticleexplainstheinnerworkingsofthisverywell,sowe'lljustcoverthebasicshere.
thisandarrowfunctions
InJavaScript,thisisavariablethat'ssetwhenafunctioniscalled.Thismakesitaverypowerfulandflexiblefeature,butitcomesatthecostofalwayshavingtoknowaboutthecontextthatafunctionisexecutingin.Thisisnotoriouslyconfusing,especiallywhenreturningafunctionorpassingafunctionasanargument.
Let'slookatanexample:
letdeck={suits:["hearts","spades","clubs","diamonds"],cards:Array(52),createCardPicker:function(){returnfunction(){letpickedCard=Math.floor(Math.random()*52);letpickedSuit=Math.floor(pickedCard/13);
return{suit:this.suits[pickedSuit],card:pickedCard%13};};},};
letcardPicker=deck.createCardPicker();letpickedCard=cardPicker();
alert("card:"+pickedCard.card+"of"+pickedCard.suit);
NoticethatcreateCardPickerisafunctionthatitselfreturnsafunction.Ifwetriedtoruntheexample,wewouldgetanerrorinsteadoftheexpectedalertbox.
http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/
-
ThisisbecausethethisbeingusedinthefunctioncreatedbycreateCardPickerwillbesettowindowinsteadofourdeckobject.That'sbecausewecallcardPicker()onitsown.Atop-levelnon-methodsyntaxcalllikethiswillusewindowforthis.(Note:understrictmode,thiswillbeundefinedratherthanwindow).
Wecanfixthisbymakingsurethefunctionisboundtothecorrectthisbeforewereturnthefunctiontobeusedlater.Thisway,regardlessofhowit'slaterused,itwillstillbeabletoseetheoriginaldeckobject.Todothis,wechangethefunctionexpressiontousetheECMAScript6arrowsyntax.Arrowfunctionscapturethethiswherethefunctioniscreatedratherthanwhereitisinvoked:
letdeck={suits:["hearts","spades","clubs","diamonds"],cards:Array(52),createCardPicker:function(){//NOTE:thelinebelowisnowanarrowfunction,allowingustocapture'this'rightherereturn()=>{letpickedCard=Math.floor(Math.random()*52);letpickedSuit=Math.floor(pickedCard/13);
return{suit:this.suits[pickedSuit],card:pickedCard%13};};},};
letcardPicker=deck.createCardPicker();letpickedCard=cardPicker();
alert("card:"+pickedCard.card+"of"+pickedCard.suit);
Evenbetter,TypeScriptwillwarnyouwhenyoumakethismistakeifyoupassthe--noImplicitThisflagtothecompiler.Itwillpointoutthatthisinthis.suits[pickedSuit]isoftypeany.
thisparameters
Unfortunately,thetypeofthis.suits[pickedSuit]isstillany.That'sbecausethiscomesfromthefunctionexpressioninsidetheobjectliteral.Tofixthis,youcanprovideanexplicitthisparameter.thisparametersarefakeparametersthat
-
comefirstintheparameterlistofafunction:
functionf(this:void){//makesure`this`isunusableinthisstandalonefunction}
Let'saddacoupleofinterfacestoourexampleabove,CardandDeck,tomakethetypesclearerandeasiertoreuse:
interfaceCard{suit:string;card:number;}
interfaceDeck{suits:string[];cards:number[];createCardPicker(this:Deck):()=>Card;}
letdeck:Deck={suits:["hearts","spades","clubs","diamonds"],cards:Array(52),//NOTE:ThefunctionnowexplicitlyspecifiesthatitscalleemustbeoftypeDeckcreateCardPicker:function(this:Deck){return()=>{letpickedCard=Math.floor(Math.random()*52);letpickedSuit=Math.floor(pickedCard/13);
return{suit:this.suits[pickedSuit],card:pickedCard%13};};},};
letcardPicker=deck.createCardPicker();letpickedCard=cardPicker();
alert("card:"+pickedCard.card+"of"+pickedCard.suit);
NowTypeScriptknowsthatcreateCardPickerexpectstobecalledonaDeckobject.ThatmeansthatthisisoftypeDecknow,notany,so--noImplicitThiswillnotcauseanyerrors.
thisparametersincallbacks
-
Youcanalsorunintoerrorswiththisincallbacks,whenyoupassfunctionstoalibrarythatwilllatercallthem.Becausethelibrarythatcallsyourcallbackwillcallitlikeanormalfunction,thiswillbeundefined.Withsomeworkyoucanusethisparameterstopreventerrorswithcallbackstoo.First,thelibraryauthorneedstoannotatethecallbacktypewiththis:
interfaceUIElement{addClickListener(onclick:(this:void,e:Event)=>void):void;}
this:voidmeansthataddClickListenerexpectsonclicktobeafunctionthatdoesnotrequireathistype.Second,annotateyourcallingcodewiththis:
classHandler{info:string;onClickBad(this:Handler,e:Event){//oops,used`this`here.usingthiscallbackwouldcrashatruntimethis.info=e.message;}}
leth=newHandler();uiElement.addClickListener(h.onClickBad);//error!
Argumentoftype'(this:Handler,e:Event)=>void'isnotassignabletoparameteroftype'(this:void,e:Event)=>void'.The'this'typesofeachsignatureareincompatible.Type'void'isnotassignabletotype'Handler'.
Withthisannotated,youmakeitexplicitthatonClickBadmustbecalledonaninstanceofHandler.ThenTypeScriptwilldetectthataddClickListenerrequiresafunctionthathasthis:void.Tofixtheerror,changethetypeofthis:
classHandler{info:string;onClickGood(this:void,e:Event){//can'tuse`this`herebecauseit'softypevoid!console.log("clicked!");}}
leth=newHandler();uiElement.addClickListener(h.onClickGood);
BecauseonClickGoodspecifiesitsthistypeasvoid,itislegaltopasstoaddClickListener.Ofcourse,thisalsomeansthatitcan'tusethis.info.Ifyou
-
wantboththenyou'llhavetouseanarrowfunction:
classHandler{info:string;onClickGood=(e:Event)=>{this.info=e.message;};}
Thisworksbecausearrowfunctionsusetheouterthis,soyoucanalwayspassthemtosomethingthatexpectsthis:void.ThedownsideisthatonearrowfunctioniscreatedperobjectoftypeHandler.Methods,ontheotherhand,areonlycreatedonceandattachedtoHandler'sprototype.TheyaresharedbetweenallobjectsoftypeHandler.
Overloads
JavaScriptisinherentlyaverydynamiclanguage.It'snotuncommonforasingleJavaScriptfunctiontoreturndifferenttypesofobjectsbasedontheshapeoftheargumentspassedin.
letsuits=["hearts","spades","clubs","diamonds"];
functionpickCard(x:any):any{//Checktoseeifwe'reworkingwithanobject/array//ifso,theygaveusthedeckandwe'llpickthecardif(typeofx=="object"){letpickedCard=Math.floor(Math.random()*x.length);returnpickedCard;}//Otherwisejustletthempickthecardelseif(typeofx=="number"){letpickedSuit=Math.floor(x/13);return{suit:suits[pickedSuit],card:x%13};}}
letmyDeck=[{suit:"diamonds",card:2},{suit:"spades",card:10},{suit:"hearts",card:4},];
-
letpickedCard1=myDeck[pickCard(myDeck)];alert("card:"+pickedCard1.card+"of"+pickedCard1.suit);
letpickedCard2=pickCard(15);alert("card:"+pickedCard2.card+"of"+pickedCard2.suit);
Here,thepickCardfunctionwillreturntwodifferentthingsbasedonwhattheuserhaspassedin.Iftheuserspassesinanobjectthatrepresentsthedeck,thefunctionwillpickthecard.Iftheuserpicksthecard,wetellthemwhichcardthey'vepicked.Buthowdowedescribethistothetypesystem?
Theansweristosupplymultiplefunctiontypesforthesamefunctionasalistofoverloads.Thislistiswhatthecompilerwillusetoresolvefunctioncalls.Let'screatealistofoverloadsthatdescribewhatourpickCardacceptsandwhatitreturns.
letsuits=["hearts","spades","clubs","diamonds"];
functionpickCard(x:{suit:string;card:number}[]):number;functionpickCard(x:number):{suit:string;card:number};functionpickCard(x:any):any{//Checktoseeifwe'reworkingwithanobject/array//ifso,theygaveusthedeckandwe'llpickthecardif(typeofx=="object"){letpickedCard=Math.floor(Math.random()*x.length);returnpickedCard;}//Otherwisejustletthempickthecardelseif(typeofx=="number"){letpickedSuit=Math.floor(x/13);return{suit:suits[pickedSuit],card:x%13};}}
letmyDeck=[{suit:"diamonds",card:2},{suit:"spades",card:10},{suit:"hearts",card:4},];
letpickedCard1=myDeck[pickCard(myDeck)];alert("card:"+pickedCard1.card+"of"+pickedCard1.suit);
letpickedCard2=pickCard(15);alert("card:"+pickedCard2.card+"of"+pickedCard2.suit);
-
Withthischange,theoverloadsnowgiveustypecheckedcallstothepickCardfunction.
Inorderforthecompilertopickthecorrecttypecheck,itfollowsasimilarprocesstotheunderlyingJavaScript.Itlooksattheoverloadlistand,proceedingwiththefirstoverload,attemptstocallthefunctionwiththeprovidedparameters.Ifitfindsamatch,itpicksthisoverloadasthecorrectoverload.Forthisreason,it'scustomarytoorderoverloadsfrommostspecifictoleastspecific.
NotethatthefunctionpickCard(x):anypieceisnotpartoftheoverloadlist,soitonlyhastwooverloads:onethattakesanobjectandonethattakesanumber.CallingpickCardwithanyotherparametertypeswouldcauseanerror.
-
LiteralTypesAliteralisamoreconcretesub-typeofacollectivetype.Whatthismeansisthat"HelloWorld"isastring,butastringisnot"HelloWorld"insidethetypesystem.
TherearethreesetsofliteraltypesavailableinTypeScripttoday:strings,numbers,andbooleans;byusingliteraltypesyoucanallowanexactvaluewhichastring,number,orbooleanmusthave.
LiteralNarrowing
Whenyoudeclareavariableviavarorlet,youaretellingthecompilerthatthereisthechancethatthisvariablewillchangeitscontents.Incontrast,usingconsttodeclareavariablewillinformTypeScriptthatthisobjectwillneverchange.
//We'remakingaguaranteethatthisvariable//helloWorldwillneverchange,byusingconst.
//So,TypeScriptsetsthetypetobe"HelloWorld",notstringconsthelloWorld="HelloWorld";
//Ontheotherhand,aletcanchange,andsothecompilerdeclaresitastringlethiWorld="HiWorld";
Theprocessofgoingfromaninfinitenumberofpotentialcases(thereareaninfinitenumberofpossiblestringvalues)toasmaller,finitenumberofpotentialcase(inhelloWorld'scase:1)iscallednarrowing.
StringLiteralTypes
Inpracticestringliteraltypescombinenicelywithuniontypes,typeguards,andtypealiases.Youcanusethesefeaturestogethertogetenum-likebehaviorwithstrings.
https://www.typescriptlang.org/play/#code/PTAEHUFMHICdNAWwIYGsCWA7A5qZpsBXZWZTAF0gXIAtlzRb0BnUANxPWQCMAbSAFAhQNSL14B7cBNi8AJqADu6caEyQ2kWKADGdHJAA0obgE9QhZllw6JmZuQB0AoWADKE4wBVTAB0huOrDovgzMkOSstNR+1BImCABEABJikhAy8onGmBJh5ME4Arb2DKLiUpkKALygKWnx0rJyiQDcLsIA8piMoqB5otr6csb4-Aw6ZLr62EZ4mArM8dG6Eoi+KlqgcpA6vCSQrOgM+A6F2ALjIuhN8qC1KegZzW1AAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYAsBWAUAC4CeADpKAKICGiAlgHYDmoAvKAESQ2QC0D7oAD4cuiXnACuBAcM7c+9HpOkBuPHgDGAGxqJQAVQCSFLZAC2kegVABvPKFBV6tM1QKQAFABMAHqnoSZgBGMAA0oF5E-oEh0OGiDIyo1HRMAJS29g6gtABmoB4JTKwsbHJiCuwZdtnZIKAAdE1ZDgC+oJBaYjn5hTSJJWWi4lJVmbXtnd15BUXMpUPyDEqj1S2gk13kNbWg9YYEAOR6JHCIdEGmoAQAFm6giHAWcPTkGpJaXqDQXBo31zdaIh1g56kEiDlGPQEAMiJJoNdSJA9LdJIwbg11q0stjsXhTNYglICC9WKBXgB3AzGUwWKweNJqIkEEn0BpOFxuTwABnCvJES3oVSZxJe7OcrncHn5-PYEleNCIwqAAhttps://www.typescriptlang.org/play/#code/GYVwdgxgLglg9mABAJzgGzQERhApgCgEoAuRARkQB9EAmKxAZnoBZ6BWegNkQG8AoRClxQQyJPgCyAQygALAHTA0cOMkkyFyKWAAmcALZFEAKkSdCiANTkLUgM7l6dak2qtqHapwDcfAL58fBAIdlBCdiBoYQC8KOhYOASE3kAhttps://www.typescriptlang.org/play/#code/PQKhAIGECcFMEMAusDO57gLbwA7gMawB2ycAJuouADYD2+w1S4IwAUGbPk3OAGYBXIvkQBLWkXApYiATgCyuABT4JfUQHMAXOEU5IazQEodAN1qiyAbjbBg4ALRP8AxE4dtRJWND7xCurgGROoa4ADebOA0RNrgRAKYAEY+NtFMiDoJyalR4GLUsADKogBesDoAHOAAPuAAjABsteAAzABMNgC+bGzSsgrK4TFxDgDsrQB0AJytAKztACztADQ0SDqLAAyTE1uN9WsFxWUVDc1dRlZAAhttps://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgGpwDbACZzMAexAGUBXBJAZ0uQG8AoZZYS9LbALmTClIgG5GyKBDiUiXEKQwZBAX3r1QkWIhRsceQiABicYBlIi6Qlhs7J4GSgKEixE5JR6gA5vMVgAngAd1mTXwiACUISmkwZABeNADcIJJyKhoAH1j2LSI9AyMBIA
-
strings.
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{//It'spossiblethatsomeonecouldreachthis//byignoringyourtypesthough.}}}
letbutton=newUIElement();button.animate(0,0,"ease-in");button.animate(0,0,"uneasy");
Argumentoftype'"uneasy"'isnotassignabletoparameteroftype'Easing'.
Youcanpassanyofthethreeallowedstrings,butanyotherstringwillgivetheerror
Argumentoftype'"uneasy"'isnotassignabletoparameteroftype'"ease-in"|"ease-out"|"ease-in-out"'
Stringliteraltypescanbeusedinthesamewaytodistinguishoverloads:
functioncreateElement(tagName:"img"):HTMLImageElement;functioncreateElement(tagName:"input"):HTMLInputElement;//...moreoverloads...functioncreateElement(tagName:string):Element{//...codegoeshere...}
NumericLiteralTypes
TypeScriptalsohasnumericliteraltypes,whichactthesameasthestringliteralsabove.
functionrollDice():1|2|3|4|5|6{
-
return(Math.floor(Math.random()*6)+1)as1|2|3|4|5|6;}
constresult=rollDice();
Acommoncasefortheiruseisfordescribingconfigvalues:
interfaceMapConfig{lng:number;lat:number;tileSize:8|16|32;}
setupMap({lng:-73.935242,lat:40.73061,tileSize:16});
BooleanLiteralTypes
TypeScriptalsohasbooleanliteraltypes.Youmightusethesetoconstrainobjectvalueswhosepropertiesareinterrelated.
interfaceValidationSuccess{isValid:true;reason:null;}
interfaceValidationFailure{isValid:false;reason:string;}
typeValidationResult=ValidationSuccess|ValidationFailure;
-
UnionsandIntersectionTypesSofar,thehandbookhascoveredtypeswhichareatomicobjects.However,asyoumodelmoretypesyoufindyourselflookingfortoolswhichletyoucomposeorcombineexistingtypesinsteadofcreatingthemfromscratch.
IntersectionandUniontypesareoneofthewaysinwhichyoucancomposetypes.
UnionTypes
Occasionally,you'llrunintoalibrarythatexpectsaparametertobeeitheranumberorastring.Forinstance,takethefollowingfunction:
/***Takesastringandadds"padding"totheleft.*If'padding'isastring,then'padding'isappendedtotheleftside.*If'padding'isanumber,thenthatnumberofspacesisaddedtotheleftside.*/functionpadLeft(value:string,padding:any){if(typeofpadding==="number"){returnArray(padding+1).join("")+value;}if(typeofpadding==="string"){returnpadding+value;}thrownewError(`Expectedstringornumber,got'${typeofpadding}'.`}
padLeft("Helloworld",4);//returns"Helloworld"
TheproblemwithpadLeftintheaboveexampleisthatitspaddingparameteristypedasany.Thatmeansthatwecancallitwithanargumentthat'sneitheranumbernorastring,butTypeScriptwillbeokaywithit.
//passesatcompiletime,failsatruntime.letindentedString=padLeft("Helloworld",true);
Intraditionalobject-orientedcode,wemightabstractoverthetwotypesby
https://www.typescriptlang.org/play/#code/PQKhCgAIUgVBDA1gUwM6XpVAXATgSwDsBzDQgEw3PPQCIAHeao42ybAe3YAtlIAbZADNsAOigwAkkMgByRsxKzI+dJhwESAGh7JCcheRbLVGevT3lklTroHDsWfFfHRI0g0yNKVayIQBXAFsAI2RcHWxefSj4R0DQ8MgOGVRGAGM0XyorGy4ovkERJxcJYHAhAMJ07HwOfQUAGQcACgA3eH4A5AAuLDwWHUMWPvhCAE8ASkgAbygVGRbscYsUyGGSSABeHchaBLDcWmm5yDPIXGRsANx9AEFcXHhxlo3SAGpIAEZJ0QArDhEFpsY6QT4dLrIADc8wAvvN8ItlqsZG9trtaBoWKDTudLtdbusvCwwZAId0YWd4WcorgOAB3fzIRkAUUeHFwLQABiyAB4WGrWfqaUgc-zBQ46YgcRyyAAkM2RyDWb1hslEXMmMPh4CarVoAAlkPx+Fx6Rz+ORaDoACxayDAYAXK43Qh0c6QI0ms0Wq1AAhttps://www.typescriptlang.org/play/#code/CYUwxgNghgTiAEAzArgOzAFwJYHtXwAcpgAZERDACgDcoJkQAueAZwxi1QHMAaQ44Jy7MoqAJ4BKZmw7cA3ACgA9EvgBaDWGQYNa5aqIsWIFvCgZ4YHAFsCWCAmzWQfRFHunz8GGicgAdAoOFpygqBggwADK7ELwALz8pORUAEQAEiAQEDjwAO44MBDAqXzsDBJyQAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYAsBWAUMAFSF6iGgAqAhgNaSKhWiIAu0AlgHYDmjnAJo378GAIgAOVYV26jQLOPIAWkUABtIAMxYA6UuQCSm0AHJJ0nidDsGTVhx4AaZZE6nz-GVZuNx41-yQggou6loszOyBemSgRu5SnpbWtqCcAK4AtgBGMM4sKm4FVBEZOTCgcMaIkgDG9ClCgcGKBaoa2pHR+sB4mumctSzscG7mADLhABQAblRq6ZCo9jLOHjLLbDKgAD5pWbnQAJSgAN6koCCgOjd4AL54eBoRXIGcLEEAyls8oAC8oAm01EAAlIGo1IoAO4INT8UT5aCLI4AbiAAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYME4BQuBLAOwBcYAzAQwGNJQAhA6AE1AG9dRRyAbATwAUASlQA3OAWYBuTqB6U+AUQDmyxMLETpuAL75iZaFVqgAYgUQALdrMQB3AgFsNocZJld5S1epGutMnq4zJDU8tB05ACuRNQkBHBEoMqQJADKjpQ8PAAKqS7mVqAAPgxM2rg8qaAADtUAvMmpGVm5+UIydSQAdF4qasIyuCCgAPJE-KCUopQE8gBGVaDEoIl0cOSgJJZ0JHZwtXCIiASLu3x1iLhd3fZOg0Ahttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYME4BQAXATwAdJQA5SfAdwQGsAZOAQwBMBLAOwHMBlfZvjIBeUAG9coUIgFDUAIgA2LDj3kBuXAF9NBEmUo16AMWbtFkVv0Ejxk6bMgKAZmYusN9gMZxWT0JwArgC2AEYwmjq4eqQUVLTQdLyBXl6QiIjWQqCiElIyNgqIKWkZnlLQ6cRwnIj+eVKg+Oz4Fqgy0Fzcmo2grIHQguw1qEFhEfb5IcHM0ITt+J08PaBRUSCgALTbXoH425sxBvH0WSL2AD5xRolMbF1nl9cJdKbmlo9SV4YvyanpmUcumcgU4XmaNVAym43BgAAoCnJnqdHABKBZLbh2KQbABK7G4AAt8AE4NRQAAVfS8LydYgk1hwdKkkl0Thk0DUQnsLyE0BwZxNQlkfCEyqQewbapCTjNZiKJr6RAOGygHyBRSsUDhAB00RxYApcy6TTgoGY-wy5tAxHgpGgRE53N5oHYiE4AHISYhCbNLJKwBb4Fb5QqiKRldRzArBm6yMxOKAYPBoPZEZAdT4-LoDaAAEKEaRR-C8k2Q9MAGkp1Np7HpaoTAVm8HJorIoOGnADfTJia4at8ZGcynJCflhEQbrTxZdCMcOvTqOxjS8zDqoCUKi68mQk0alXwA0T8gAIr3lPceDrr+UV2uyPJXO8PLvermKcLFbFgoEZNrjjcrxuB8jigMKlQVnuuaIGaFqlJOPBCmQAAGWaQMhoDOOwkCaq6yqIMwzgSm+oAHkeoDIQAorACCgAAJGI6aZoOWg9tQnAXqo3DISsUiruu8jFJaiA7lBpFUORyFnuxnGWPRjHzpUiDVLUGbNK0kCsZs8lMUpKl1Au0yzIQWg8fYWjaEAAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYBsWBQAXATwAdJQA5SfAdwQGsAZOAQwBMBLAOwHMBlfZvjIBeUAG9QiAUNQAiADYsOPWaAC+AbgIkylGvQBizdvMit+gkeMnTIcgGbHTrWRtABjOKzuhOAVwBbACMYdS0iUgoqWmg6Xj93d0hERAshUFExXFAbSzlEBKSU12zQaGTiOE5EHyycnPx2fFNUKWgubi160FY-aEF2KtR-YJgu+oKAgOZoQlb8dp5xzVwVkFAAWi33P3wtje1IvRi6A3gAgGFmdwALMzSrOtyZUFl7c4B9d2u7kpz2VjzRadUrlRCVao+Y70eKJZKpWwAbVkYIhNVkAF0tCtDrpojDbBlSgAfKL6WJMNgdB4ksknIwme62WnQ2KwooIyws-GxM5wS4-JmWLS4ex+TjuRpVUCKbjcGAAChQdIJlgAlOJSohqE1bqAlQA6KTqzXdb41V6KKkqZClbrlfB9TiWpQdMqQACOfmS+D+9XNZDeTjMslt3RyDqdoAABo5GaxQDr8DcPF4yAASMSIA2ebxqaPjHIB14FOHFMPhyPQZ2ybhwfDu8FVdHLVZAAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYBsWBQAXATwAdJQA5SfAdwQGsAZOAQwBMBLAOwHMBlfZvjIBeUAG9QiAUNQAiADYsOPWaAC+AbgIkylGvQBizdvMit+gkeMnTIcgGbHTrWRtABjOKzuhOAVwBbACMYdS0iUgoqWmg6Xj93d0hERAshUFEJKUs5RASklNVNbUi9GLoDeACAYWZ3AAszNKss2wcqgH13OsairRLdaPpmjNxQUAAfKP1YpjYuPlsxyenyoxMmpfGpsuH85NStld3Yyrgans3LfpBQAFoH9z98B7vcez9Od3x2OE5QRTcbgwAAUKFWw1sAEpUFJoAtxMtENR2PgGqAwQA6bJCKGI8bjbqIMgKJQLWTIZYE0DQKh+aD-UnzHg0yAARz8yXwripHmYxNAskcGxclOp41p+Hp-wABsLnKAUfh6h4vGQACRiRCYzzeNQyrTUokkvKJA4U3kSukMwXcOD4VmIYh-Yk88ZqXBqIAhttps://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGYAsBWAUAC4CeADpKAHKQEDuCA1gDJwCGAJgJYB2A5gMoEWBcgF5QAb1CJBw1ACIANq0685oAL4BuQqXJVaDAGIsOCyGwFDREqTMjyAZibNs5m0AGM4be6C4BXAFsAIxgNbWIySmo6aHo+fw8PSERES2FQMUlpK3lEROTUtS0dKP1Y+kN4QIBhFg8AC3N062y7R2qAfQ96puLtUr0YhhbMvFBQAB9ogzjmdm5+O3GpmYrjU2blienykYKUtO3VvbiquFrerattEFAAWkePfwJH+7wHfy4PAg44LlALFSMAIVAAbjAABQAD1QXEgEOgAEo4QiwuIVgQGvAaH5ILiAKKwBCQuQAVXh0LIP3MoDgwQAVpAfvJQABqUDQpHadR4D5fH5-AFKHg8KEoNYjOwo2zQRYSFaIGgcAiNUCQxAAOhywiRComEx6iHIimUizkyBWBtA0Go-mgANNC14NsgAEd-CkCG4rZ4gSanJtXJbrRNbQR7QCAAaBlygZVYzzecgAEnEWq8PnUUe01qNJvySUOFt9YbtDtAch4cAIrsQJH+xp91p8Tn8CgIIdD4cjgOB0FBaOgGu5K156iAA
-
creatingahierarchyoftypes.Whilethisismuchmoreexplicit,it'salsoalittlebitoverkill.OneofthenicethingsabouttheoriginalversionofpadLeftwasthatwewereabletojustpassinprimitives.Thatmeantthatusagewassimpleandconcise.Thisnewapproachalsowouldn'thelpifwewerejusttryingtouseafunctionthatalreadyexistselsewhere.
Insteadofany,wecanuseauniontypeforthepaddingparameter:
/***Takesastringandadds"padding"totheleft.*If'padding'isastring,then'padding'isappendedtotheleftside.*If'padding'isanumber,thenthatnumberofspacesisaddedtotheleftside.*/functionpadLeft(value:string,padding:string|number){//...}
letindentedString=padLeft("Helloworld",true);
Argumentoftype'boolean'isnotassignabletoparameteroftype'string|number'.
Auniontypedescribesavaluethatcanbeoneofseveraltypes.Weusetheverticalbar(|)toseparateeachtype,sonumber|string|booleanisthetypeofavaluethatcanbeanumber,astring,oraboolean.
UnionswithCommonFields
Ifwehaveavaluethatisauniontype,wecanonlyaccessmembersthatarecommontoalltypesintheunion.
interfaceBird{fly():void;layEggs():void;}
interfaceFish{swim():void;layEggs():void;}
declarefunctiongetSmallPet():Fish|Bird;
-
letpet=getSmallPet();pet.layEggs();
//Onlyavailableinoneofthetwopossibletypespet.swim();
Property'swim'doesnotexistontype'Bird|Fish'.Property'swim'doesnotexistontype'Bird'.
Uniontypescanbeabittrickyhere,butitjusttakesabitofintuitiontogetusedto.IfavaluehasthetypeA|B,weonlyknowforcertainthatithasmembersthatbothAandBhave.Inthisexample,Birdhasamembernamedfly.Wecan'tbesurewhetheravariabletypedasBird|Fishhasaflymethod.IfthevariableisreallyaFishatruntime,thencallingpet.fly()willfail.
DiscriminatingUnions
AcommontechniqueforworkingwithunionsistohaveasinglefieldwhichusesliteraltypeswhichyoucanusetoletTypeScriptnarrowdownthepossiblecurrenttype.Forexample,we'regoingtocreateaunionofthreetypeswhichhaveasinglesharedfield.
typeNetworkLoadingState={state:"loading";};typeNetworkFailedState={state:"failed";code:number;};typeNetworkSuccessState={state:"success";response:{title:string;duration:number;summary:string;};};//Createatypewhichrepresentsonlyoneoftheabovetypes//butyouaren'tsurewhichitisyet.typeNetworkState=|NetworkLoadingState|NetworkFailedState|NetworkSuccessState;
-
Alloftheabovetypeshaveafieldnamedstate,andthentheyalsohavetheirownfields:
NetworkLoadingState NetworkFailedState NetworkSuccessState
state state statecode response
GiventhestatefieldiscommonineverytypeinsideNetworkState-itissafeforyourcodetoaccesswithoutanexistencecheck.
Withstateasaliteraltype,youcancomparethevalueofstatetotheequivalentstringandTypeScriptwillknowwhichtypeiscurrentlybeingused.
NetworkLoadingState NetworkFailedState NetworkSuccessState
"loading" "failed" "success"
Inthiscase,youcanuseaswitchstatementtonarrowdownwhichtypeisrepresentedatruntime:
typeNetworkState=|NetworkLoadingState|NetworkFailedState|NetworkSuccessState;
functionlogger(state:NetworkState):string{//RightnowTypeScriptdoesnotknowwhichofthethree//potentialtypesstatecouldbe.
//Tryingtoaccessapropertywhichisn'tshared//acrossalltypeswillraiseanerrorstate.code;
Property'code'doesnotexistontype'NetworkState'.Property'code'doesnotexistontype'NetworkLoadingState'.
//Byswitchingonstate,TypeScriptcannarrowtheunion//downincodeflowanalysisswitch(state.state){case"loading":return"Downloading...";case"failed"://ThetypemustbeNetworkFailedStatehere,//soaccessingthe`code`fieldissafereturn`Error${state.code}downloading`;
-
case"success":return`Downloaded${state.response.title}-${state.response.summary}}
UnionExhaustivenesschecking
Wewouldlikethecompilertotelluswhenwedon'tcoverallvariantsofthediscriminatedunion.Forexample,ifweaddNetworkFromCachedStatetoNetworkState,weneedtoupdateloggeraswell:
typeNetworkFromCachedState={state:"from_cache";id:string;response:NetworkSuccessState["response"];};
typeNetworkState=|NetworkLoadingState|NetworkFailedState|NetworkSuccessState|NetworkFromCachedState;
functionlogger(s:NetworkState){switch(s.state){case"loading":return"loadingrequest";case"failed":return`failedwithcode${s.code}`;case"success":return"gotresponse";}}
Therearetwowaystodothis.Thefirstistoturnon--strictNullChecksandspecifyareturntype: