Handbook - Classes - TypeScript

文章推薦指數: 80 %
投票人數:10人

Traditional JavaScript uses functions and prototype-based inheritance to build ... This class has three members: a property called greeting , a constructor, ... Wasthispagehelpful?GetStartedTSfortheNewProgrammerTypeScriptforJSProgrammersTSforJava/C#ProgrammersTSforFunctionalProgrammersTypeScriptToolingin5minutesHandbookTheTypeScriptHandbookTheBasicsEverydayTypesNarrowingMoreonFunctionsObjectTypesTypeManipulationCreatingTypesfromTypesGenericsKeyofTypeOperatorTypeofTypeOperatorIndexedAccessTypesConditionalTypesMappedTypesTemplateLiteralTypesClassesModulesReferenceUtilityTypesCheatSheetsDecoratorsDeclarationMergingEnumsIteratorsandGeneratorsJSXMixinsModulesModuleResolutionNamespacesNamespacesandModulesSymbolsTriple-SlashDirectivesTypeCompatibilityTypeInferenceVariableDeclarationTutorialsASP.NETCoreGulpDOMManipulationMigratingfromJavaScriptUsingBabelwithTypeScriptWhat'sNewOverviewTypeScript4.5TypeScript4.4TypeScript4.3TypeScript4.2TypeScript4.1TypeScript4.0TypeScript3.9TypeScript3.8TypeScript3.7TypeScript3.6TypeScript3.5TypeScript3.4TypeScript3.3TypeScript3.2TypeScript3.1TypeScript3.0TypeScript2.9TypeScript2.8TypeScript2.7TypeScript2.6TypeScript2.5TypeScript2.4TypeScript2.3TypeScript2.2TypeScript2.1TypeScript2.0TypeScript1.8TypeScript1.7TypeScript1.6TypeScript1.5TypeScript1.4TypeScript1.3TypeScript1.1DeclarationFilesIntroductionDeclarationReferenceLibraryStructures.d.tsTemplatesModules.d.tsModule:PluginModule:ClassModule:FunctionGlobal.d.tsGlobal:ModifyingModuleDo'sandDon'tsDeepDivePublishingConsumptionJavaScriptJSProjectsUtilizingTypeScriptTypeCheckingJavaScriptFilesJSDocReferenceCreating.d.tsFilesfrom.jsfilesProjectConfigurationWhatisatsconfig.jsonCompilerOptionsinMSBuildTSConfigReferencetscCLIOptionsProjectReferencesIntegratingwithBuildToolsConfiguringWatchNightlyBuildsThispagehasbeendeprecatedThishandbookpagehasbeenreplaced,gotothenewpageGotonewpageClassesTraditionalJavaScriptusesfunctionsandprototype-basedinheritancetobuildupreusablecomponents,butthismayfeelabitawkwardtoprogrammersmorecomfortablewithanobject-orientedapproach,whereclassesinheritfunctionalityandobjectsarebuiltfromtheseclasses. StartingwithECMAScript2015,alsoknownasECMAScript6,JavaScriptprogrammerscanbuildtheirapplicationsusingthisobject-orientedclass-basedapproach. InTypeScript,weallowdeveloperstousethesetechniquesnow,andcompilethemdowntoJavaScriptthatworksacrossallmajorbrowsersandplatforms,withouthavingtowaitforthenextversionofJavaScript. Classes Let’stakealookatasimpleclass-basedexample: tsclassGreeter{greeting:string; constructor(message:string){this.greeting=message;} greet(){return"Hello,"+this.greeting;}} letgreeter=newGreeter("world");Try Thesyntaxshouldlookfamiliarifyou’veusedC#orJavabefore. WedeclareanewclassGreeter.Thisclasshasthreemembers:apropertycalledgreeting,aconstructor,andamethodgreet. You’llnoticethatintheclasswhenwerefertooneofthemembersoftheclassweprependthis.. Thisdenotesthatit’samemberaccess. InthelastlineweconstructaninstanceoftheGreeterclassusingnew. Thiscallsintotheconstructorwedefinedearlier,creatinganewobjectwiththeGreetershape,andrunningtheconstructortoinitializeit. Inheritance InTypeScript,wecanusecommonobject-orientedpatterns. Oneofthemostfundamentalpatternsinclass-basedprogrammingisbeingabletoextendexistingclassestocreatenewonesusinginheritance. Let’stakealookatanexample: tsclassAnimal{move(distanceInMeters:number=0){console.log(`Animalmoved${distanceInMeters}m.`);}} classDogextendsAnimal{bark(){console.log("Woof!Woof!");}} constdog=newDog();dog.bark();dog.move(10);dog.bark();Try Thisexampleshowsthemostbasicinheritancefeature:classesinheritpropertiesandmethodsfrombaseclasses. Here,DogisaderivedclassthatderivesfromtheAnimalbaseclassusingtheextendskeyword. Derivedclassesareoftencalledsubclasses,andbaseclassesareoftencalledsuperclasses. BecauseDogextendsthefunctionalityfromAnimal,wewereabletocreateaninstanceofDogthatcouldbothbark()andmove(). Let’snowlookatamorecomplexexample. tsclassAnimal{name:string;constructor(theName:string){this.name=theName;}move(distanceInMeters:number=0){console.log(`${this.name}moved${distanceInMeters}m.`);}} classSnakeextendsAnimal{constructor(name:string){super(name);}move(distanceInMeters=5){console.log("Slithering...");super.move(distanceInMeters);}} classHorseextendsAnimal{constructor(name:string){super(name);}move(distanceInMeters=45){console.log("Galloping...");super.move(distanceInMeters);}} letsam=newSnake("SammythePython");lettom:Animal=newHorse("TommythePalomino"); sam.move();tom.move(34);Try Thisexamplecoversafewotherfeatureswedidn’tpreviouslymention. Again,weseetheextendskeywordsusedtocreatetwonewsubclassesofAnimal:HorseandSnake. Onedifferencefromthepriorexampleisthateachderivedclassthatcontainsaconstructorfunctionmustcallsuper()whichwillexecutetheconstructorofthebaseclass. What’smore,beforeweeveraccessapropertyonthisinaconstructorbody,wehavetocallsuper(). ThisisanimportantrulethatTypeScriptwillenforce. Theexamplealsoshowshowtooverridemethodsinthebaseclasswithmethodsthatarespecializedforthesubclass. HerebothSnakeandHorsecreateamovemethodthatoverridesthemovefromAnimal,givingitfunctionalityspecifictoeachclass. NotethateventhoughtomisdeclaredasanAnimal,sinceitsvalueisaHorse,callingtom.move(34)willcalltheoverridingmethodinHorse: Slithering... SammythePythonmoved5m. Galloping... TommythePalominomoved34m. Public,private,andprotectedmodifiers Publicbydefault Inourexamples,we’vebeenabletofreelyaccessthemembersthatwedeclaredthroughoutourprograms. Ifyou’refamiliarwithclassesinotherlanguages,youmayhavenoticedintheaboveexampleswehaven’thadtousethewordpublictoaccomplishthis;forinstance,C#requiresthateachmemberbeexplicitlylabeledpublictobevisible. InTypeScript,eachmemberispublicbydefault. Youmaystillmarkamemberpublicexplicitly. WecouldhavewrittentheAnimalclassfromtheprevioussectioninthefollowingway: tsclassAnimal{publicname:string; publicconstructor(theName:string){this.name=theName;} publicmove(distanceInMeters:number){console.log(`${this.name}moved${distanceInMeters}m.`);}}Try ECMAScriptPrivateFields WithTypeScript3.8,TypeScriptsupportsthenewJavaScriptsyntaxforprivatefields: tsclassAnimal{#name:string;constructor(theName:string){this.#name=theName;}} newAnimal("Cat").#name;Property'#name'isnotaccessibleoutsideclass'Animal'becauseithasaprivateidentifier.18013Property'#name'isnotaccessibleoutsideclass'Animal'becauseithasaprivateidentifier.Try ThissyntaxisbuiltintotheJavaScriptruntimeandcanhavebetterguaranteesabouttheisolationofeachprivatefield. Rightnow,thebestdocumentationfortheseprivatefieldsisintheTypeScript3.8releasenotes. UnderstandingTypeScript’sprivate TypeScriptalsohasitsownwaytodeclareamemberasbeingmarkedprivate,itcannotbeaccessedfromoutsideofitscontainingclass.Forexample: tsclassAnimal{privatename:string; constructor(theName:string){this.name=theName;}} newAnimal("Cat").name;Property'name'isprivateandonlyaccessiblewithinclass'Animal'.2341Property'name'isprivateandonlyaccessiblewithinclass'Animal'.Try TypeScriptisastructuraltypesystem. Whenwecomparetwodifferenttypes,regardlessofwheretheycamefrom,ifthetypesofallmembersarecompatible,thenwesaythetypesthemselvesarecompatible. However,whencomparingtypesthathaveprivateandprotectedmembers,wetreatthesetypesdifferently. Fortwotypestobeconsideredcompatible,ifoneofthemhasaprivatemember,thentheothermusthaveaprivatememberthatoriginatedinthesamedeclaration. Thesameappliestoprotectedmembers. Let’slookatanexampletobetterseehowthisplaysoutinpractice: tsclassAnimal{privatename:string;constructor(theName:string){this.name=theName;}} classRhinoextendsAnimal{constructor(){super("Rhino");}} classEmployee{privatename:string;constructor(theName:string){this.name=theName;}} letanimal=newAnimal("Goat");letrhino=newRhino();letemployee=newEmployee("Bob"); animal=rhino;animal=employee;Type'Employee'isnotassignabletotype'Animal'. Typeshaveseparatedeclarationsofaprivateproperty'name'.2322Type'Employee'isnotassignabletotype'Animal'. Typeshaveseparatedeclarationsofaprivateproperty'name'.Try Inthisexample,wehaveanAnimalandaRhino,withRhinobeingasubclassofAnimal. WealsohaveanewclassEmployeethatlooksidenticaltoAnimalintermsofshape. Wecreatesomeinstancesoftheseclassesandthentrytoassignthemtoeachothertoseewhatwillhappen. BecauseAnimalandRhinosharetheprivatesideoftheirshapefromthesamedeclarationofprivatename:stringinAnimal,theyarecompatible.However,thisisnotthecaseforEmployee. WhenwetrytoassignfromanEmployeetoAnimalwegetanerrorthatthesetypesarenotcompatible. EventhoughEmployeealsohasaprivatemembercalledname,it’snottheonewedeclaredinAnimal. Understandingprotected Theprotectedmodifieractsmuchliketheprivatemodifierwiththeexceptionthatmembersdeclaredprotectedcanalsobeaccessedwithinderivingclasses.Forexample, tsclassPerson{protectedname:string;constructor(name:string){this.name=name;}} classEmployeeextendsPerson{privatedepartment:string; constructor(name:string,department:string){super(name);this.department=department;} publicgetElevatorPitch(){return`Hello,mynameis${this.name}andIworkin${this.department}.`;}} lethoward=newEmployee("Howard","Sales");console.log(howard.getElevatorPitch());console.log(howard.name);Property'name'isprotectedandonlyaccessiblewithinclass'Person'anditssubclasses.2445Property'name'isprotectedandonlyaccessiblewithinclass'Person'anditssubclasses.Try Noticethatwhilewecan’tusenamefromoutsideofPerson,wecanstilluseitfromwithinaninstancemethodofEmployeebecauseEmployeederivesfromPerson. Aconstructormayalsobemarkedprotected. Thismeansthattheclasscannotbeinstantiatedoutsideofitscontainingclass,butcanbeextended.Forexample, tsclassPerson{protectedname:string;protectedconstructor(theName:string){this.name=theName;}} //EmployeecanextendPersonclassEmployeeextendsPerson{privatedepartment:string; constructor(name:string,department:string){super(name);this.department=department;} publicgetElevatorPitch(){return`Hello,mynameis${this.name}andIworkin${this.department}.`;}} lethoward=newEmployee("Howard","Sales");letjohn=newPerson("John");Constructorofclass'Person'isprotectedandonlyaccessiblewithintheclassdeclaration.2674Constructorofclass'Person'isprotectedandonlyaccessiblewithintheclassdeclaration.Try Readonlymodifier Youcanmakepropertiesreadonlybyusingthereadonlykeyword. Readonlypropertiesmustbeinitializedattheirdeclarationorintheconstructor. tsclassOctopus{readonlyname:string;readonlynumberOfLegs:number=8; constructor(theName:string){this.name=theName;}} letdad=newOctopus("Manwiththe8stronglegs");dad.name="Manwiththe3-piecesuit";Cannotassignto'name'becauseitisaread-onlyproperty.2540Cannotassignto'name'becauseitisaread-onlyproperty.Try Parameterproperties Inourlastexample,wehadtodeclareareadonlymembernameandaconstructorparametertheNameintheOctopusclass.ThisisneededinordertohavethevalueoftheNameaccessibleaftertheOctopusconstructorisexecuted. Parameterpropertiesletyoucreateandinitializeamemberinoneplace. Here’safurtherrevisionofthepreviousOctopusclassusingaparameterproperty: tsclassOctopus{readonlynumberOfLegs:number=8;constructor(readonlyname:string){}} letdad=newOctopus("Manwiththe8stronglegs");dad.name;Try NoticehowwedroppedtheNamealtogetherandjustusetheshortenedreadonlyname:stringparameterontheconstructortocreateandinitializethenamemember. We’veconsolidatedthedeclarationsandassignmentintoonelocation. Parameterpropertiesaredeclaredbyprefixingaconstructorparameterwithanaccessibilitymodifierorreadonly,orboth. Usingprivateforaparameterpropertydeclaresandinitializesaprivatemember;likewise,thesameisdoneforpublic,protected,andreadonly. Accessors TypeScriptsupportsgetters/settersasawayofinterceptingaccessestoamemberofanobject. Thisgivesyouawayofhavingfiner-grainedcontroloverhowamemberisaccessedoneachobject. Let’sconvertasimpleclasstousegetandset. First,let’sstartwithanexamplewithoutgettersandsetters. tsclassEmployee{fullName:string;} letemployee=newEmployee();employee.fullName="BobSmith"; if(employee.fullName){console.log(employee.fullName);}Try WhileallowingpeopletorandomlysetfullNamedirectlyisprettyhandy,wemayalsowantenforcesomeconstraintswhenfullNameisset. Inthisversion,weaddasetterthatchecksthelengthofthenewNametomakesureit’scompatiblewiththemax-lengthofourbackingdatabasefield.Ifitisn’twethrowanerrornotifyingclientcodethatsomethingwentwrong. Topreserveexistingfunctionality,wealsoaddasimplegetterthatretrievesfullNameunmodified. tsconstfullNameMaxLength=10; classEmployee{private_fullName:string=""; getfullName():string{returnthis._fullName;} setfullName(newName:string){if(newName&&newName.length>fullNameMaxLength){thrownewError("fullNamehasamaxlengthof"+fullNameMaxLength);} this._fullName=newName;}} letemployee=newEmployee();employee.fullName="BobSmith"; if(employee.fullName){console.log(employee.fullName);}Try Toprovetoourselvesthatouraccessorisnowcheckingthelengthofvalues,wecanattempttoassignanamelongerthan10charactersandverifythatwegetanerror. Acoupleofthingstonoteaboutaccessors: First,accessorsrequireyoutosetthecompilertooutputECMAScript5orhigher. DownlevelingtoECMAScript3isnotsupported. Second,accessorswithagetandnosetareautomaticallyinferredtobereadonly. Thisishelpfulwhengeneratinga.d.tsfilefromyourcode,becauseusersofyourpropertycanseethattheycan’tchangeit. StaticProperties Uptothispoint,we’veonlytalkedabouttheinstancemembersoftheclass,thosethatshowupontheobjectwhenit’sinstantiated. Wecanalsocreatestaticmembersofaclass,thosethatarevisibleontheclassitselfratherthanontheinstances. Inthisexample,weusestaticontheorigin,asit’sageneralvalueforallgrids. Eachinstanceaccessesthisvaluethroughprependingthenameoftheclass. Similarlytoprependingthis.infrontofinstanceaccesses,hereweprependGrid.infrontofstaticaccesses. tsclassGrid{staticorigin={x:0,y:0}; calculateDistanceFromOrigin(point:{x:number;y:number}){letxDist=point.x-Grid.origin.x;letyDist=point.y-Grid.origin.y;returnMath.sqrt(xDist*xDist+yDist*yDist)/this.scale;} constructor(publicscale:number){}} letgrid1=newGrid(1.0);//1xscaleletgrid2=newGrid(5.0);//5xscale console.log(grid1.calculateDistanceFromOrigin({x:10,y:10}));console.log(grid2.calculateDistanceFromOrigin({x:10,y:10}));Try AbstractClasses Abstractclassesarebaseclassesfromwhichotherclassesmaybederived. Theymaynotbeinstantiateddirectly. Unlikeaninterface,anabstractclassmaycontainimplementationdetailsforitsmembers. Theabstractkeywordisusedtodefineabstractclassesaswellasabstractmethodswithinanabstractclass. tsabstractclassAnimal{abstractmakeSound():void; move():void{console.log("roamingtheearth...");}}Try Methodswithinanabstractclassthataremarkedasabstractdonotcontainanimplementationandmustbeimplementedinderivedclasses. Abstractmethodsshareasimilarsyntaxtointerfacemethods. Bothdefinethesignatureofamethodwithoutincludingamethodbody. However,abstractmethodsmustincludetheabstractkeywordandmayoptionallyincludeaccessmodifiers. tsabstractclassDepartment{constructor(publicname:string){} printName():void{console.log("Departmentname:"+this.name);} abstractprintMeeting():void;//mustbeimplementedinderivedclasses} classAccountingDepartmentextendsDepartment{constructor(){super("AccountingandAuditing");//constructorsinderivedclassesmustcallsuper()} printMeeting():void{console.log("TheAccountingDepartmentmeetseachMondayat10am.");} generateReports():void{console.log("Generatingaccountingreports...");}} letdepartment:Department;//oktocreateareferencetoanabstracttypedepartment=newDepartment();//error:cannotcreateaninstanceofanabstractclassCannotcreateaninstanceofanabstractclass.2511Cannotcreateaninstanceofanabstractclass.department=newAccountingDepartment();//oktocreateandassignanon-abstractsubclassdepartment.printName();department.printMeeting();department.generateReports();//error:departmentisnotoftypeAccountingDepartment,cannotaccessgenerateReportsProperty'generateReports'doesnotexistontype'Department'.2339Property'generateReports'doesnotexistontype'Department'.Try AdvancedTechniques Constructorfunctions WhenyoudeclareaclassinTypeScript,youareactuallycreatingmultipledeclarationsatthesametime. Thefirstisthetypeoftheinstanceoftheclass. tsclassGreeter{greeting:string; constructor(message:string){this.greeting=message;} greet(){return"Hello,"+this.greeting;}} letgreeter:Greeter;greeter=newGreeter("world");console.log(greeter.greet());//"Hello,world"Try Here,whenwesayletgreeter:Greeter,we’reusingGreeterasthetypeofinstancesoftheclassGreeter. Thisisalmostsecondnaturetoprogrammersfromotherobject-orientedlanguages. We’realsocreatinganothervaluethatwecalltheconstructorfunction. Thisisthefunctionthatiscalledwhenwenewupinstancesoftheclass. Toseewhatthislookslikeinpractice,let’stakealookattheJavaScriptcreatedbytheaboveexample: tsletGreeter=(function(){functionGreeter(message){this.greeting=message;} Greeter.prototype.greet=function(){return"Hello,"+this.greeting;}; returnGreeter;})(); letgreeter;greeter=newGreeter("world");console.log(greeter.greet());//"Hello,world"Try Here,letGreeterisgoingtobeassignedtheconstructorfunction. Whenwecallnewandrunthisfunction,wegetaninstanceoftheclass. Theconstructorfunctionalsocontainsallofthestaticmembersoftheclass. Anotherwaytothinkofeachclassisthatthereisaninstancesideandastaticside. Let’smodifytheexampleabittoshowthisdifference: tsclassGreeter{staticstandardGreeting="Hello,there";greeting:string;greet(){if(this.greeting){return"Hello,"+this.greeting;}else{returnGreeter.standardGreeting;}}} letgreeter1:Greeter;greeter1=newGreeter();console.log(greeter1.greet());//"Hello,there" letgreeterMaker:typeofGreeter=Greeter;greeterMaker.standardGreeting="Heythere!"; letgreeter2:Greeter=newgreeterMaker();console.log(greeter2.greet());//"Heythere!" letgreeter3:Greeter;greeter3=newGreeter();console.log(greeter3.greet());//"Heythere!"Try Inthisexample,greeter1workssimilarlytobefore. WeinstantiatetheGreeterclass,andusethisobject. Thiswehaveseenbefore. Next,wethenusetheclassdirectly. HerewecreateanewvariablecalledgreeterMaker. Thisvariablewillholdtheclassitself,orsaidanotherwayitsconstructorfunction. HereweusetypeofGreeter,thatis“givemethetypeoftheGreeterclassitself”ratherthantheinstancetype. Or,moreprecisely,“givemethetypeofthesymbolcalledGreeter,”whichisthetypeoftheconstructorfunction. ThistypewillcontainallofthestaticmembersofGreeteralongwiththeconstructorthatcreatesinstancesoftheGreeterclass. WeshowthisbyusingnewongreeterMaker,creatingnewinstancesofGreeterandinvokingthemasbefore. Itisalsogoodtomentionthatchangingstaticpropertyisfrownedupon,heregreeter3has"Heythere!"insteadof"Hello,there"onstandardGreeting. Usingaclassasaninterface Aswesaidintheprevioussection,aclassdeclarationcreatestwothings:atyperepresentinginstancesoftheclassandaconstructorfunction. Becauseclassescreatetypes,youcanusetheminthesameplacesyouwouldbeabletouseinterfaces. tsclassPoint{x:number;y:number;} interfacePoint3dextendsPoint{z:number;} letpoint3d:Point3d={x:1,y:2,z:3};TryOnthispageClassesInheritancePublic,private,andprotectedmodifiersPublicbydefaultECMAScriptPrivateFieldsUnderstandingTypeScript’sprivateUnderstandingprotectedReadonlymodifierParameterpropertiesAccessorsStaticPropertiesAbstractClassesAdvancedTechniquesConstructorfunctionsUsingaclassasaninterfaceIsthispagehelpful?YesNoTheTypeScriptdocsareanopensourceproject.HelpusimprovethesepagesbysendingaPullRequest❤Contributorstothispage:RCDROTNSBW24+Lastupdated:Mar07,2022 MSG



請為這篇文章評分?