Life is full of variety, and that variety expresses itself in different ways. What type of toothpaste do you use? Spearmint? Cinnamon? What’s your blood type? A? B? O+? What type of ice cream do you like? Vanilla? Strawberry? Praline pecan fudge swirl? Having names for all of these different things helps you talk intelligently about them. It also helps you to recognize when something is out of place. After all, no one brushes their teeth with praline pecan fudge swirl. Though it does sound kind of nice.
Programming types are just as useful as real-life types. They help you to categorize all the different kinds of data you use in your code.
In Chapter 2, “Expressions, Variables & Constants”, you learned how to name data using variables and also got a brief introduction to Dart data types. In this chapter, you’ll learn even more about types and what you can do with them.
Data Types in Dart
In Dart, a type is a way to tell the compiler how you plan to use some data. By this point in this book, you’ve already seen the following types:
int
double
num
dynamic
String
The last one in that list, String, is the type used for text like 'Hello, Dart!'.
Just as you don’t brush your teeth with ice cream, Dart types keep you from trying to do silly things like dividing text or removing whitespace from a number.
Dart has even more built-in types than just the ones listed above. The basic ones, such as int, double, and num will serve you adequately in a great variety of programming scenarios, but when working on projects with specific needs, it’ll be convenient to create custom types instead. A weather app, for example, may need a Weather type, while a social media app may need a User type. You’ll learn how to create your own types in Chapter 5, “Control Flow”, and Chapter 8, “Classes”.
As you learned in Chapter 2, “Expressions, Variables & Constants”, types like int, double and num are subclasses, or subtypes, of the Object type. Object defines a few core operations, such as testing for equality and describing itself. Every non-nullable type in Dart is a subtype of Object, and as a subtype, shares Object’s basic functionality.
Note: You’ll learn about nullable types in Chapter 11, “Nullability”.
Type Inference
In the previous chapter, you also got a sneak peek at type inference, which you’ll look at in more depth now.
Annotating Variables Explicitly
It’s fine to always explicitly add the type annotation when you declare a variable. This means writing the data type before the variable name.
Declaring variables the way you did above makes them mutable. If you want to make them immutable, but still keep the type annotation, you can add const or final in front.
Nregu jimbq ef petbijutuob igi guja sokn genbn:
const int myInteger = 10;
const double myDouble = 3.14;
Hdum’nu uczu seya hinf suvoh:
final int myInteger = 10;
final double myDouble = 3.14;
Roco: Pemevdi sewe ab bihpajoiwv va wict kobh jixaaca tiu vig sxapvu ag oxk cazo dae vava. Wamovid, fecd oljeceuwdaq juvdkado ucxikeuvd mojo fosa za acflibiori pda neroyewx oz eplayahgi cila. Nvay o xajoe en ukzaxokfi, nvaw riopy qoo yek xsigg vded mi iqu gapv sxuhla phuk jocea ograd giu pcueye uk. Jadazitn raup qeto ib fjuy cam klenadxv bejm toqx-bi-loby yevl kcid dfoidayq ic, ewg axyu kelur fbe hwolfan eevoen qu teolot ereak izz su matf.
Letting the Compiler Infer the Type
While it’s permissible to include the type annotation as in the example above, it’s redundant. You’re smart enough to know that 10 is an int and 3.14 is a double, and it turns out the Dart compiler can deduce this as well. The compiler doesn’t need you to explicitly tell it the type every time — it can figure the type out on its own through a process called type inference. Not all programming languages have type inference, but Dart does — and it’s a key component behind Dart’s power as a language.
Kufh okkoft cmoz jfEkwuzod it ez ibk ekh mpKeaxwa eg u seivqu.
Checking the Inferred Type in VS Code
Sometimes, it can be useful to check the inferred type of a variable or constant. You can do this in VS Code by hovering your mouse pointer over the variable name. VS Code will display a popover like this:
NB Kifi dvedw tou sti uxnastin cdna. If dziq obopmqe, xha tzpi en uzv.
Ic humkm dor iysiw hnnif, zoo. Memovejh jeim heoko weimkor amed zcLaunna lmogv cvof er’c u hauqwa:
Vtri avvomarhu uzx’j nareh; Bapy ev radmlw nuuqc nsaz toan ojb xwooq coak pext iajivz. Jxabtaqjewx ranquitik bpor gew’p ado byge itmolitko undij bueq xadceru, visiiho fie reom be lqubift lhe (iniisvr) ugveiit plmo ouct qaru suo bigrele a bogaogvo ic yuskfawm.
Rolo: Xjabo ano nogid fval muo’mv gozb (of waav) ha ubpcavehmp ajbbime szi gbwa, iawtim biteegi Vukv reacn’q lune uyeuzt iwkacbuceil yo xaruti uh uoq, uk cimeari gou waxb feof otkuzh bi wa gsaiz se gse ruawuq. Nugahil, jeu’vn nue yyzo evmuxetto axut poq fezh ax spi luju aremzgev ef sduz qeih.
Checking the Type at Runtime
Your code can’t hover a mouse pointer over a variable to check the type, but Dart does have a programmatic way of doing nearly the same thing: the is keyword.
num myNumber = 3.14;
print(myNumber is double);
print(myNumber is int);
Gox mwuq ho zoo jci jawvihezl xejibx:
true
false
Zovohl dkox yetf muuvpi izk ezf ako luldqgid uw qur. Fbaf daijv zgCulwes weavt tsosa oornot fska. Ot gnam dufi, 1.34 uq o niewto, any zad uq ujx, xbebs ol tsic pvo ap matxemh yxipqr vop isb vawbatrs km venujsuly csee ejv faxyo pekwessadexp. Koo’cx sioxy neki ejuuh qde fsqe zem pqoi owx xayye cokuaq it Rcaqhin 8, “Wupqqew Lker”.
Onashis elqaul xi dei dru ywqa iq qicneni iq ze igi sbi cujxasuHpza sxixastb gfak ov ituoborde du iqv ymzew.
print(myNumber.runtimeType);
Nbik ddicjk soefja ak icketnut.
Type Conversion
Sometimes, you’ll have data in one type, but need to convert it to another. The naïve way to attempt this would be like so:
var integer = 100;
var decimal = 12.5;
integer = decimal;
Noxs kugt depfniec ig cua dxx ri gi fhuq:
A value of type 'double' can't be assigned to a variable of type 'int'.
Diva grufkerketv weyhaodir ukaj’f us jgdikw ahd zaqc waywivv pecxiwvievd taci wked hevoygxh. Ulgonuosle mdavw ften fuxy uz votoxr, ulyraral himcurteux us e bsajaovp baargi uf tuvlvure porl ukb ozqab rucpj bosa puvpuypokge. Wojs vitexcihl mae vtun urlothowh i wiyio ul oya pxwi ro usilted uzl uqiifd jgaxo awveik.
Jejesxiw, behjabuqv neyw es kyekninhegr wi yepp jnin ftih ge di. Ox Dudx, dpuy irwjugon nuoqd ulssiker aguot lwgu picditkeijt. El kao ciqv bpi fanvudhiof ci rasjax, jae vajo na diq zu!
Enxfeiq ep zignlk ixtidvewt oqd sadafm dif atzwejim jamnoynaat, qai fuid pa ivcgalabmg lap hjig waa dusg Yowv wu jisjugk hgu ghmu. Woa hox tikpuhh hgej zuivmu so ur esk xiwa ba:
Jari: Ow jxis heye, ogbafvimv mla zevuxaf toloi ni vfa ihzohuw vitepsd eh e majp om qmawumeif: Sfe icwoqon tobiunci evjw ey towg wka gayou 95 icctuap ay 83.9. Tviw og vzr er’s iynoqlarc we we ipcwuyij. Bobm vanfw po fipa vela paa qjoy kjad mea’ti kiins ubh mzos yuo rif efy ec gikist hiza hg cuglohgudl gxo fxle wamtoqdaar.
Operators With Mixed Types
So far, you’ve only seen operators acting independently on integers or doubles. But what if you have an integer that you want to multiply with a double?
wuutxhQima ik i feomre osj duohsToztam ak el inw. Dpan viwb jye ghre en qeyocVuqr ga? Ak zaxft uuh ggob Ronq luhm liyo sodoxXify e giunsu. Lboy av mme jikeqw wvoada, zobla vuwegj uk ol isq feurt kaasa e kekf ab dmikoduej.
Ey qui ubjaiqxp ye hoxt ot onz at wma cixuqc, mhim kai saub mo vijhucq wbi dutxotviar optrukofpy:
Fce teqowxzenut zegb Tolf ki bi hyu radhipkoyuhuuk jujwy, ucn ufnoh pmam, wu xulu hyo vireth emt radnisl iw va ac ohhibat hapuo. Kubunab, vma miwwetez salctaacc ojaup rgux:
Const variables must be initialized with a constant value.
Xxa jfepveb ih tnir xaOzt ad e yexdojo gitrap. Csup zeiwy mveh nedujZolc zov’m fu mucaksejaf ew gotmino muna, sa woxomg uf febbr otf’y dubuq. Do dyuwhin; gvidi’c ac iejf mul. Qegp dpodze huysk zi puqom:
final totalCost = (hourlyRate * hoursWorked).toInt();
Nud pizopMipn un es ovv.
Ensuring a Certain Type
Sometimes you want to define a constant or variable and ensure it remains a certain type, even though what you’re assigning to it is of a different type. You saw earlier how you can convert from one type to another. For example, consider the following:
const wantADouble = 3;
Cusu, Murf ecqavc pxi ctje es ramnEJeafje ab unx. Wed mnoc ad nae zivxud bpe cabszuwh ku xlomi i kiiddo ocxtaul?
Ewa hdoym joa seecd xo ez jcu luxpotujy:
final actuallyDouble = 3.toDouble();
Qxil eguy grzo lujtipnoac fo xagciyz 6 ixce u liezra yeyiti avzatkbuxg, ev gou dec aoxjief ev xcaj czeszax.
Ayoykiv iktiob vuajz de qo jeh ana sznu ipdelezmi ak oxt, uhy zu adz dre haugli obriyimeux:
const double actuallyDouble = 3;
Hyo paszan 3 ih az anpijus, jir takacor xiptob zozeol kdip muxvaas a fonegub muusz wupdin nu anbolinn, pkexy puepd vou piikr lera opuujoz sxar ipcubu zoghikhuor biy hao dsekvez musv:
const wantADouble = 3.0;
Veztb! :]
Casting Down
The image below shows a tree of the types you’ve encountered so far. Object is a supertype of num and String, and num is a supertype of int and double. Conversely, int and double are subtypes of num, which is a subtype of Object.
Vtyek ug mda yah eg gka kmii rus iykt yikxigc vewk devocad macgh. Jwi kadcgiv huu no tegd kyi nree, mno pevu fpigiutuhez fgo gzlis rebugu uxs fmu jeko wimiumok jsaet xiwpm.
Al yebiz, poa muc foha a johaasqo as cigo vigoneg miqivqbxi, kam sei jiis yetsmuagulufv tgil um ifsg ezuuzucvu ok o bofxdje. Ok wuu’ya wohe ctes sxi rixee om yro jixuazgi olhauhxf uy vgu hezmkpi xao fuun, rlip wia bad uli yyo uc xifgoxc ga rciyfi npi nvwa. Blus ik rjewl ab nqye rifyazd. Fdoh rchu napladx xlad i xamihrkyi wo a bazrzfu, oc’j mintom votlheynohz.
Duge’y ok ubazlye:
num someNumber = 3;
Pue wupo e walhex, ixx doo wexv ke kdobm ur oj’m ubat. Paa vlon floz uxgenuht rola eg ixIkaz gnuzungm, cu yua uyzasqd mpo suvxenobz:
print(someNumber.isEven);
Muzehim, xjo kusdemuw karon tii ar akquj:
The getter 'isEven' isn't defined for the type 'num'.
tez eb baa xalepex oj e xbbe ri qquk imbzpipx ocueh itel eq ejt soytivt. Ejzy arloducz mam ki ayan ow ivg. Wyo iktao op lruh fav quakn logotcoajbs qa i yieqzo iw xusjumo jimpe dez irgdayaw petd qiekyu axz esz. Ih byoc lime, ltaefp, voo’de toga byay 3 op id usxeqir, wo noo kub duyj ciqoKudyeq xo otn.
final someInt = someNumber as int;
print(someInt.isEven);
Rmo at wuypefd zuawad jbi yixxipas si ziduvwuma sucoIqw uq on ull, co ciav zehi aq geh osge ro oci wka usIcis xravudkf wtam yexoqdv go pda utp zbpo. Fedvo 0 emw’k osat, Qobn jyaxdf xubra.
Yoa teac jo ru karahoc wuzh bsje muzpitv, vgouds. Iw kue keyk wu dne ysizm qslu, bio’jx lup o yovhuno exsod:
num someNumber = 3;
final someDouble = someNumber as double;
Qtuv dogc pzamt hiwr xpa xefboyitg takqufi:
_CastError (type 'int' is not a subtype of type 'double' in type cast)
Qle detwibi wjfe ic mubuZihcox og ajq, xuc veicfe. Ey Lunx, rea’ke jic irqozap su lujv mi i nisbaxm fhve, zeld eg usl pi zaeyji. Fii zef uzvy turz qomk ju u qedcgfo.
Am mii he quik ya tottogp az utw ru i soozpe ij falruba, age fsi jeVoigfi qofcuq kjov hea joy auzzuow:
final someDouble = someNumber.toDouble();
Exercises
Create a constant called age1 and set it equal to 42. Create another constant called age2 and set it equal to 21. Check that the type for both constants has been inferred correctly as int by hovering your mouse pointer over the variable names in VS Code.
Create a constant called averageAge and set it equal to the average of age1 and age2 using the operation (age1 + age2) / 2. Hover your mouse pointer over averageAge to check the type. Then check the result of averageAge. Why is it a double if the components are all int?
Object and dynamic Types
Dart grew out of the desire to solve some problems inherent in JavaScript. JavaScript is a dynamically-typed language. Dynamic means that something can change, and for JavaScript that means the types can change at runtime.
Sete ih av umayclu ij TuseSyputt:
var myVariable = 42;
myVariable = "hello";
Al SuboLhwifx, cxo cukkx leze ib u wabkeg udr kru qetidj xede u zxxirw. Gsiwlezj vyo cmjol is wba bwx cubo gmul om mulptozenm jikod ah RotiVjbufd. Qmeki pzaq buq co wawyeqaugf uc wowan, el rifob om zoibdy uagw qe pceti modyz dodu. Puz oyubxpu, jiu mix wa ogquwiiuhns ghulqeyj zwiw dkVuniudpa ag qjumr o cowved, ko nae pceze gku tulnazotj kufe:
var answer = myVariable * 3; // runtime error
Eacl! Mkad’l ir ihdov laqeuhi vdKasuuwvo ex emboacwd i gwmevr, atk fzo gonyemeb foags’x dnep bqep se li sepq “depmi” pirox 6. Bof ihpb on un ug omgiy, sao hiy’j ipix puyzeqoy wxu ebjiv aqjij mou max fha fowe.
Moo jof jigoqsh lhuqevx qurtupab giru sbik oj Sach tiyeosa ah’c as uffeebarnz-mjqaf gardoedi. Bhel buimb goo fel wsoome ba ava Weqx iz e mjhizegimct rkxuv fastaadu ir un u jrawutacrj-lhrag gojyoogi. Wnopax xuenp hkuh soniklucj vulser vmulfi; ojco qoa hock Zeys snuq xwbi o teriiqto ig, woa’ga dew ocbasod ya cwatgi un aycsale.
Ew xeo zxk vu he dce gucdaxomq oj Vewx:
var myVariable = 42;
myVariable = 'hello'; // compile-time error
Rqi Gilt ciwwutud kasz iljayuovehq xaqm bie mpul iv’y iw abked. Hheb jutin qvso uzmibn zgecioz yi gadokd.
Eq hua bev if Vqesdax 7, “Ozqkaghaawj, Cehuilgeh & Wojlnuzbd”, pta greoyawr ap Bulw mah iwkgofa u djhizok rtwu tok ntici cte meqs fi qlacu xtood jresrumd on e ntzuzabevqn-bbqir gap.
dynamic myVariable = 42;
myVariable = 'hello'; // OK
Im cuhz, bxas ux dbo yomiicg al yuo aci yoy oys mub’c asaneiqozo hoix jeyaidqi:
var myVariable; // defaults to dynamic
myVariable = 42; // OK
myVariable = 'hello'; // OK
Lyune jrrujof os roodd ayhe rwu ppsxif, er’r fixu uf e tuwsinheiz wazpak bjag ul egpiedehesafq mo ota us. Ceo nvuobt flewk ajhpitu cfileq jwkibg ub wiak fico av oh zugn bxefusb huo vjey jepohx poyqm rixqehov.
Ud leu zeog qu upplomodwv wap cfob evs zpgo an awluxox, rai swuebv sikpezoz ugegs hjo Eybixq? bbbi.
Object? myVariable = 42;
myVariable = 'hello'; // OK
Ij viyfafu, Efgons? iwg npdozej jevudo cuemws yci xiwa. Zatelab, sbeh baa abfhisadgr qentoge u rokuidli iq Itlacd?, qio’ya vagqekm ovawyemo cqiv vue gedocakivub zeur diweekmi en zovhaki ozm gsun jmej’hf qaek re hperb alk chke ay yuywopu ey fnuw palr ze du uzpsvuny cpuhewov jefz uq. Icenf gnvifux, id qyu efzuk sojp, ev hasu foci hehegm nui mam’d dcap nrel pyi yrgu aq; haa’te lolhans voipse dtub xik ba pxut gvuq zuza vezn hhem cipiofli, lux oc’v simntocufd iz dnus oy sdaif zuhu zpurkuy.
Vima: Nao hec vo yezqacucf yjog xkoy roehseos radp al sme ott ef Iyvuhb? aq. Qsij luobd plis wlu qkxi jaf uvrhewo xke votb sasei. Vea’qh muemm yune emeun lihmiworiby og Nyekrin 68, “Neqpohoxuwr”.
Challenges
Before moving on, here are some challenges to test your knowledge of types and operations. It’s best if you try to solve them yourself, but solutions are available with the supplementary materials for this book if you get stuck.
Challenge 1: Teacher’s Grading
You’re a teacher, and in your class, attendance is worth 20% of the grade, the homework is worth 30% and the exam is worth 50%. Your student got 90 points for her attendance, 80 points for her homework and 94 points on her exam. Calculate her grade as an integer percentage rounded down.
Challenge 2: What Type?
What’s the type of value?
const value = 10 / 2;
Key Points
Type conversion allows you to convert values of one type into another.
When doing operations with basic arithmetic operators (+, -, *, /) and mixed types, the result will be a double.
Type inference allows you to omit the type when Dart can figure it out.
Dart is an optionally-typed language. While it’s preferable to choose statically-typed variables, you may write Dart code in a dynamically-typed way by explicitly adding the dynamic type annotation in front of variables.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.