Basic Types Introduction For programs to be useful, we need to be able to work with some of the simplest units of data: numbers, strings, structures, boolean values, and the like. In TypeScript, TypeScript, we support much the same types as you would expect in avaScript, with a convenient enumeration type thrown in to help things along.
Boolean The most basic datatype is the simple true!false value, which avaScript and TypeScript TypeScript call a boolean value. let isDone:
boolean = boolean = false false; ;
Number "s in avaScript, all numbers in TypeScript TypeScript are floating point values. These floating point numbers get the type number. In addition to hexadecimal and decimal literals, TypeScript TypeScript also supports binary and octal literals introduced in #$%"Script &'(). let decimal: number number = = 6; let hex: number number = = 0xf00d; let binary: number number = = 0b1010; let octal: number number = = 0o744;
String "nother fundamental part of creating programs in avaScript for webpages and servers alike is working with textual data. "s in other languages, we use the type string to refer to these textual datatypes. ust like avaScript, TypeScript TypeScript also uses double *uotes +" or single *uotes +' to surround string data. let color:
string = "blue" string = "blue"; ; color = 'red' 'red'; ;
-ou can also use template strings, strings, which can span multiple lines and have embedded expressions. These strings are surrounded by the backtick!back*uote +` character, and embedded expressions are of the form ${ expr }. let fullame: string string = = let age: number number = = #7; let sentence: string string = =
!ob obbington!; !$ello% my name is & fullame ()
*'ll be & age + 1 ( years old next month)!;
This is e*uivalent to declaring sentence like so: let sentence:
string = string = "$ello% my name is " + " + fullame + "),n,n" "),n,n" + + "*'ll be " " + + -age + 1. + " years old next month)"; month)";
Array TypeScript, like avaScript, allows you to work with arrays of values. "rray "rray types can be written in one of two ways. In the first, you use the type of the elements followed by [] to denote an array of that element type:
String "nother fundamental part of creating programs in avaScript for webpages and servers alike is working with textual data. "s in other languages, we use the type string to refer to these textual datatypes. ust like avaScript, TypeScript TypeScript also uses double *uotes +" or single *uotes +' to surround string data. let color:
string = "blue" string = "blue"; ; color = 'red' 'red'; ;
-ou can also use template strings, strings, which can span multiple lines and have embedded expressions. These strings are surrounded by the backtick!back*uote +` character, and embedded expressions are of the form ${ expr }. let fullame: string string = = let age: number number = = #7; let sentence: string string = =
!ob obbington!; !$ello% my name is & fullame ()
*'ll be & age + 1 ( years old next month)!;
This is e*uivalent to declaring sentence like so: let sentence:
string = string = "$ello% my name is " + " + fullame + "),n,n" "),n,n" + + "*'ll be " " + + -age + 1. + " years old next month)"; month)";
Array TypeScript, like avaScript, allows you to work with arrays of values. "rray "rray types can be written in one of two ways. In the first, you use the type of the elements followed by [] to denote an array of that element type:
let list:
number/ number / = /1% % #;
The second way uses a generic array type, Array
: let list:
2rray3 2rray 3number number = /1% % #;
Tuple T uple Tuple types allow you to express an array where the type of a fixed number of elements is known, but need not be the same. For example, you may want to represent a value as a pair of a string and a number: 55 Declare a tule tye let x: /string /string% % number number; ; 55 *nitialie it x = /"hello" /"hello"% % 10; 55 89 55 *nitialie it incorrectly x = /10% "hello" "hello"; ; 55 rror
hen accessing an element with a known index, the correct type is retrieved: console)log-x/0)substr-1..; 55 89 console)log-x/0)substr-1..; console)log-x/1)substr-1..; console )log-x/1)substr-1..; 55 rror% 'number' does not hae 'substr'
hen accessing an element outside the set of known indices, a union type is used instead: x/# = ")to?tring-..; 55 89% 'string' and 'number' both hae console)log-x/>)to?tring-..; 'to?tring' x/6 = true true; ; 55 rror% 'boolean' isn't 'string number'
/nion types are an advanced topic that we0ll cover in a later chapter.
Enum " helpful addition to the standard set of datatypes from avaScript is the enum. "s in languages like $1, an enum is a way of giving more friendly names to sets of numeric values. enum @olor @olor Aed% Breen% lue( let c: @olor = @olor)Breen;
2y default, enums begin numbering their members starting at 0. -ou -ou can change this by manually setting the value of one of its members. For example, we can start the previous example at instead of 0: enum @olor @olor Aed = 1% Breen% let c: @olor = @olor)Breen;
lue(
3r, 3r, even manually set all the values in the enum: enum @olor @olor Aed = 1% Breen = let c: @olor = @olor)Breen;
% lue = 4(
" handy feature of enums is that you can also go from a numeric value to the name of that value in the enum. For example, if we had the value ! but weren0t sure what that mapped to in the olor enum above, we could look up the corresponding name: enum @olor @olor Aed = 1% Breen% lue( let colorame: string string = = @olor/;
alert-colorame.;
Any
e may need to describe the type of variables that we do not know when we are writing an application. These values may come from dynamic content, e.g. from the user or a 4rd party library. In these cases, we want to opt5out of type5checking and let the values pass through compile5time checks. To do so, we label these with the any type: let not?ure:
any = 4; not?ure = "maybe a string instead"; not?ure = false; 55 oCay% definitely a boolean
The any type is a powerful way to work with existing avaScript, allowing you to gradually opt5in and opt5out of type5checking during compilation. -ou might expect #bect to play a similar role, as it does in other languages. 2ut variables of type #bect only allow you to assign any value to them 5 you can0t call arbitrary methods on them, even ones that actually exist: let not?ure:
any = 4; not?ure)if*txists-.; 55 oCay% if*txists might exist at runtime not?ure)toixed-.; 55 oCay% toixed exists -but the comiler doesn't checC. let retty?ure:
8bEect = 4; retty?ure)toixed-.; 55 rror: Froerty 'toixed' doesn't exist on tye '8bEect')
The any type is also handy if you know some part of the type, but perhaps not all of it. For example, you may have an array but the array has a mix of different types: let list:
any/ = /1% true% "free";
list/1 = 100;
Void
%oi& is a little like the opposite of any: the absence of having any type at all. -ou may commonly see this as the return type of functions that do not return a value: function warnUser-.: void
(
alert-"Ghis is my
6eclaring variables of type %oi& is not useful because you can only assign un&eine& or null to them: let unusable:
oid = undefined;
Null and Undefned In TypeScript, both un&eine& and null actually have their own types named un&eine& and null respectively. %uch like %oi&, they0re not extremely useful on their own: 55 ot much else
2y default null and un&eine& are subtypes of all other types. That means you can assign null and un&eine& to something like number. 7owever, when using the (( strict)ull*ec+s flag, null and un&eine& are only assignable to %oi& and their respective types. This helps avoid many common errors. In cases where you want to pass in either a string or null or un&eine&, you can use the union type string , null , un&eine&. 3nce again, more on union types later on.
"s a note: we encourage the use of (( strict)ull*ec+s when possible, but for the purposes of this handbook, we will assume it is turned off.
Never The ne%er type represents the type of values that never occur. For instance, ne%er is the return type for a function expression or an arrow function expression that always throws an exception or one that never returns8 9ariables also ac*uire the type ne%er when narrowed by any type guards that can never be true. The ne%er type is a subtype of, and assignable to, every type8 however, no type is a subtype of, or assignable to, ne%er+except ne%er itself. #ven any isn0t assignable to ne%er. Some examples of functions returning ne%er: 55 unction returning neer must hae unreachable end oint function error-message: string.: never throw new rror-message.; ( 55 *nferred return tye is neer function fail-. return error-"?omething failed".; ( 55 unction returning neer must hae unreachable end oint function infiniteLoop-.: never while -true. ( (
Type assertions
Sometimes you0ll end up in a situation where you0ll know more about a value than TypeScript does. /sually this will happen when you know the type of some entity could be more specific than its current type. Type assertions are a way to tell the compiler trust me, I know what I0m doing.; " type assertion is like a type cast in other languages, but performs no special checking or restructuring of data. It has no runtime impact, and is used purely by the compiler. TypeScript assumes that you, the programmer, have performed any special checks that you need. Type assertions have two forms. 3ne is the angle5bracket; syntax: let someIalue:
any = "this is a string";
let strJength:
number = -3stringsomeIalue.)length;
"nd the other is the as5syntax: let someIalue:
any = "this is a string";
let strJength:
number = -someIalue as string.)length;
The two samples are e*uivalent. /sing one over the other is mostly a choice of preference8 however, when using TypeScript with S<, only as5style assertions are allowed.
A note about
let
-ou may0ve noticed that so far, we0ve been using the let keyword instead of avaScript0s %ar keyword which you might be more familiar with. The let keyword is actually a newer avaScript construct that TypeScript makes available. e0ll discuss the details later, but many common problems in avaScript are alleviated by using let, so you should use it instead of %ar whenever possible.
Variable Declarations Variable Declarations let and const are two relatively new types of variable declarations in avaScript. "s we mentioned earlier, let is similar to %ar in some respects, but allows users to avoid some of the common gotchas; that users run into in avaScript. const is an augmentation of let in that it prevents re5assignment to a variable. ith TypeScript being a superset of avaScript, the language naturally supports let and const. 7ere we0ll elaborate more on these new declarations and why they0re preferable to %ar. If you0ve used avaScript offhandedly, the next section might be a good way to refresh your memory. If you0re intimately familiar with all the *uirks of %ar declarations in avaScript, you might find it easier to skip ahead.
declarations
%ar
6eclaring a variable in avaScript has always traditionally been done with the %ar keyword. var a
= 10;
"s you might0ve figured out, we =ust declared a variable named a with the value 0. e can also declare a variable inside of a function: function f-. var message
(
= "$ello%
return message;
and we can also access those same variables within other functions: function f-. var a = 10; return function g-. var b = a + 1; return b;
(
(
var g
= f-.; g-.; 55 returns '11'
In this above example, g captured the variable a declared in . "t any point that g gets called, the value of a will be tied to the value of a in . #ven if g is called once is done running, it will be able to access and modify a. function f-. var a = 1;
a = ; = g-.; a = #;
var b
return b; function g-. return a;
(
(
f-.; 55 returns ''
Scoping rules %ar declarations have some odd scoping rules for those used to other languages. Take the following example: function f-should*nitialie: if -should*nitialie. var x = 10;
boolean.
(
(
return x;
f-true.; 55 returns '10' f-false.; 55 returns 'undefined'
Some readers might do a double5take at this example. The variable x was declared within the if block , and yet we were able to access it from outside that block. That0s because %ar declarations are accessible anywhere within their containing function, module, namespace, or global scope 5 all which we0ll go over later on 5 regardless of the containing block. Some people call this var scoping or function-scoping . >arameters are also function scoped. These scoping rules can cause several types of mistakes. 3ne problem they exacerbate is the fact that it is not an error to declare the same variable multiple times: function sumMatrix-matrix: number//. var sum = 0; for -var i = 0; i 3 matrix)length; i++. var currentAo< = matrix/i; for -var i = 0; i 3 currentAo<)length;
(
(
sum += currentAo
return sum;
i++.
(
%aybe it was easy to spot out for some, but the inner or5 loop will accidentally overwrite the variable i because irefers to the same function5scoped variable. "s experienced developers know by now, similar sorts of bugs slip through code reviews and can be an endless source of frustration.
Variable capturing quirs Take a *uick second to guess what the output of the following snippet is: for -var i
(
= 0; i 3 10; i++. setGimeout-function-. console)log-i.; (% 100 K i.;
For those unfamiliar, setTimeout will try to execute a function after a certain number of milliseconds +though waiting for anything else to stop running. ?eady@ Take a look: 10 10 10 10 10 10 10 10 10 10
%any avaScript developers are intimately familiar with this behavior, but if you0re surprised, you0re certainly not alone. %ost people expect the output to be
0 1 # 4 > 6 7 L M
?emember what we mentioned earlier about variable capturing@ #very function expression we pass to setTimeoutactually refers to the same i from the same scope. Aet0s take a minute to consider what that means. setTimeout will run a function after some number of milliseconds, but only after the or loop has stopped executing8 2y the time the or loop has stopped executing, the value of i is 0. So each time the given function gets called, it will print out 0B " common work around is to use an IIF# 5 an Immediately Invoked Function #xpression 5 to capture i at each iteration: for -var i
(
= 0; i 3 10; i++. 55 cature the current state of 'i' 55 by inoCing a function
This odd5looking pattern is actually pretty common. The i in the parameter list actually shadows the i declared in the or loop, but since we named them the same, we didn0t have to modify the loop body too much.
declarations
let
2y now you0ve figured out that %ar has some problems, which is precisely why let statements were introduced. "part from the keyword used, let statements are written the same way %ar statements are. let hello
= "$elloH";
The key difference is not in the syntax, but in the semantics, which we0ll now dive into.
Bloc!scoping hen a variable is declared using let, it uses what some call lexical-scoping or block-scoping . /nlike variables declared with %ar whose scopes leak out to their containing function, block5scoped variables are not visible outside of their nearest containing block or or5loop. function f-inut: let a = 100;
boolean.
if -inut.
(
(
55 ?till oCay to reference 'a' let b = a + 1; return b;
55 rror: 'b' doesn't exist here return b;
7ere, we have two local variables a and b. a0s scope is limited to the body of while b0s scope is limited to the containing i statement0s block.
9ariables declared in a catc* clause also have similar scoping rules. try throw
(
"oh noH";
catch -e.
(
console)log-"8h
55 rror: 'e' doesn't exist here console)log-e.;
"nother property of block5scoped variables is that they can0t be read or written to before they0re actually declared. hile these variables are present; throughout their scope, all points up until their declaration are part of their temporal dead zone. This is =ust a sophisticated way of saying you can0t access them before the let statement, and luckily TypeScript will let you know that. a++; 55 illegal to use 'a' before it's declared; let a;
Something to note is that you can still capture a block5 scoped variable before it0s declared. The only catch is that it0s illegal to call that function before the declaration. If targeting #S&'(), a modern runtime will throw an error8 however, right now TypeScript is permissive and won0t report this as an error. function foo-.
(
55 oCay to cature 'a' return a;
55 illegal call 'foo' before 'a' is declared 55 runtimes should thro< an error here foo-.; let a;
For more information on temporal dead Cones, see relevant content on the %oCilla 6eveloper Detwork .
"e!declarations and S#ado$ing ith %ar declarations, we mentioned that it didn0t matter how many times you declared your variables8 you =ust got one. function f-x. var x; var x;
if -true. var x;
(
(
In the above example, all declarations of x actually refer to the same x, and this is perfectly valid. This often ends up being a source of bugs. Thankfully, let declarations are not as forgiving. let x let x
= 10; = 0; 55 error: can't reNdeclare 'x' in the same scoe
The variables don0t necessarily need to both be block5scoped for TypeScript to tell us that there0s a problem. function f-x. let x = 100;
55 error: interferes
function g-. let x = 100; var x = 100;
55 error: can't hae both declarations of 'x'
(
(
That0s not to say that block5scoped variable can never be declared with a function5scoped variable. The block5scoped