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, we support much the same types as you would expect in JavaScript, with a convenient enumeration type thrown in to help things along.
Boolean
The most basic datatype is the simple true/false value, which JavaScript and TypeScript call a boolean
value.
tslet isDone:let isDone: boolean boolean = false;
Number
As in JavaScript, all numbers in TypeScript are floating point values.
These floating point numbers get the type number
.
In addition to hexadecimal and decimal literals, TypeScript also supports binary and octal literals introduced in ECMAScript 2015.
tslet decimal:let decimal: number number = 6; let hex:let hex: number number = 0xf00d; let binary:let binary: number number = 0b1010; let octal:let octal: number number = 0o744;
String
Another fundamental part of creating programs in JavaScript for webpages and servers alike is working with textual data.
As in other languages, we use the type string
to refer to these textual datatypes.
Just like JavaScript, TypeScript also uses double quotes ("
) or single quotes ('
) to surround string data.
tslet color:let color: string string = "blue"; color let color: string= "red";
You can also use template strings, which can span multiple lines and have embedded expressions.
These strings are surrounded by the backtick/backquote (`
) character, and embedded expressions are of the form ${ expr }
.
tslet fullName:let fullName: string string = `Bob Bobbington`; let age:let age: number number = 37; let sentence:let sentence: string string = `Hello, my name is ${fullNamelet fullName: string}. I'll be ${age let age: number+ 1} years old next month.`;
This is equivalent to declaring sentence
like so:
tslet sentence: string = "Hello, my name is " + fullName + ".\n\n" + "I'll be " + (age + 1) + " years old next month.";
Array
TypeScript, like JavaScript, allows you to work with arrays of values.
Array 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:
tslet list:let list: number[] number[] = [1, 2, 3];
The second way uses a generic array type, Array<elemType>
:
tslet list:let list: number[] Array<interface Array<T>number> = [1, 2, 3];
Tuple
Tuple types allow you to express an array with a fixed number of elements whose types are 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
:
ts// Declare a tuple type let x:let x: [string, number] [string, number]; // Initialize it x let x: [string, number]= ["hello", 10]; // OK // Initialize it incorrectly x let x: [string, number]= [10, "hello"]; // Error Type 'number' is not assignable to type 'string'.Type 'string' is not assignable to type 'number'.2322
2322Type 'number' is not assignable to type 'string'.Type 'string' is not assignable to type 'number'.
When accessing an element with a known index, the correct type is retrieved:
tsconsole.log(x[0].substring(1)); // OK console.log(x[1].substring(1)); // Error, 'number' does not have 'substring'
Accessing an element outside the set of known indices fails with an error:
tsx[3] = "world"; // Error, Property '3' does not exist on type '[string, number]'. console.log(x[5].toString()); // Error, Property '5' does not exist on type '[string, number]'.
Enum
A helpful addition to the standard set of datatypes from JavaScript is the enum
.
As in languages like C#, an enum is a way of giving more friendly names to sets of numeric values.
tsenum Color enum Color Red,(enum member) Color.Red = 0 Green,(enum member) Color.Green = 1 Blue(enum member) Color.Blue = 2 } let c:let c: Color Color enum Color= Color.enum ColorGreen;(enum member) Color.Green = 1
By default, enums begin numbering their members starting at 0
.
You can change this by manually setting the value of one of its members.
For example, we can start the previous example at 1
instead of 0
:
tsenum Color enum Color Red (enum member) Color.Red = 1= 1, Green,(enum member) Color.Green = 2 Blue(enum member) Color.Blue = 3 } let c:let c: Color Color enum Color= Color.enum ColorGreen;(enum member) Color.Green = 2
Or, even manually set all the values in the enum:
tsenum Color enum Color Red (enum member) Color.Red = 1= 1, Green (enum member) Color.Green = 2= 2, Blue (enum member) Color.Blue = 4= 4 } let c:let c: Color Color enum Color= Color.enum ColorGreen;(enum member) Color.Green = 2
A 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 2
but weren’t sure what that mapped to in the Color
enum above, we could look up the corresponding name:
tsenum Color enum Color Red (enum member) Color.Red = 1= 1, Green,(enum member) Color.Green = 2 Blue(enum member) Color.Blue = 3 } let colorName:let colorName: string string = Color[enum Color2]; console.var console: Consolelog((method) Console.log(message?: any, ...optionalParams: any[]): voidcolorName)let colorName: string; // Displays 'Green' as its value is 2 above
Any
We 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 3rd party library.
In these cases, we want to opt-out of type checking and let the values pass through compile-time checks.
To do so, we label these with the any
type:
tslet notSure:let notSure: any any = 4; notSure let notSure: any= "maybe a string instead"; notSure let notSure: any= false; // okay, definitely a boolean
The any
type is a powerful way to work with existing JavaScript, allowing you to gradually opt-in and opt-out of type checking during compilation.
You might expect Object
to play a similar role, as it does in other languages.
However, variables of type Object
only allow you to assign any value to them. You can’t call arbitrary methods on them, even ones that actually exist:
tslet notSure:let notSure: any any = 4; notSure.let notSure: anyifItExists(any); // okay, ifItExists might exist at runtime notSure.let notSure: anytoFixed(any); // okay, toFixed exists (but the compiler doesn't check) let prettySure:let prettySure: Object Object interface Object= 4; prettySure.let prettySure: ObjecttoFixed(any); // Error: Property 'toFixed' doesn't exist on type 'Object'. Property 'toFixed' does not exist on type 'Object'.2339Property 'toFixed' does not exist on type 'Object'.
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:
tslet list:let list: any[] any[] = [1, true, "free"]; list[let list: any[]1] = 100;
Void
void
is a little like the opposite of any
: the absence of having any type at all.
You may commonly see this as the return type of functions that do not return a value:
tsfunction warnUser(function warnUser(): void): void { console.var console: Consolelog((method) Console.log(message?: any, ...optionalParams: any[]): void"This is my warning message"); }
Declaring variables of type void
is not useful because you can only assign null
(only if --strictNullChecks
is not specified, see next section) or undefined
to them:
tslet unusable:let unusable: void void = undefinedvar undefined; unusable let unusable: void= null; // OK if `--strictNullChecks` is not given
Null and Undefined
In TypeScript, both undefined
and null
actually have their own types named undefined
and null
respectively.
Much like void
, they’re not extremely useful on their own:
ts// Not much else we can assign to these variables! let u:let u: undefined undefined = undefinedvar undefined; let n:let n: null null = null;
By default null
and undefined
are subtypes of all other types.
That means you can assign null
and undefined
to something like number
.
However, when using the --strictNullChecks
flag, null
and undefined
are only assignable to any
and their respective types (the one exception being that undefined
is also assignable to void
).
This helps avoid many common errors.
In cases where you want to pass in either a string
or null
or undefined
, you can use the union type string | null | undefined
.
Union types are an advanced topic that we’ll cover in a later chapter.
As a note: we encourage the use of
--strictNullChecks
when possible, but for the purposes of this handbook, we will assume it is turned off.
Never
The never
type represents the type of values that never occur.
For instance, never
is the return type for a function expression or an arrow function expression that always throws an exception or one that never returns;
Variables also acquire the type never
when narrowed by any type guards that can never be true.
The never
type is a subtype of, and assignable to, every type; however, no type is a subtype of, or assignable to, never
(except never
itself).
Even any
isn’t assignable to never
.
Some examples of functions returning never
:
ts// Function returning never must have unreachable end point function error(function error(message: string): nevermessage:(parameter) message: string string): never { throw new Error(var Error: ErrorConstructor new (message?: string | undefined) => Errormessage)(parameter) message: string } // Inferred return type is never function fail(function fail(): never) { return error(function error(message: string): never"Something failed"); } // Function returning never must have unreachable end point function infiniteLoop(function infiniteLoop(): never): never { while (true) {} }
Object
object
is a type that represents the non-primitive type, i.e. anything that is not number
, string
, boolean
, symbol
, null
, or undefined
.
With object
type, APIs like Object.create
can be better represented. For example:
tsdeclare function create(function create(o: object | null): voido:(parameter) o: object | null object | null): void; create(function create(o: object | null): void{ prop:(property) prop: number0 }); // OK create(function create(o: object | null): voidnull); // OK create(function create(o: object | null): void42); // Error Argument of type '42' is not assignable to parameter of type 'object | null'.2345Argument of type '42' is not assignable to parameter of type 'object | null'.create(function create(o: object | null): void"string"); // Error Argument of type '"string"' is not assignable to parameter of type 'object | null'.2345Argument of type '"string"' is not assignable to parameter of type 'object | null'.create(function create(o: object | null): voidfalse); // Error Argument of type 'false' is not assignable to parameter of type 'object | null'.2345Argument of type 'false' is not assignable to parameter of type 'object | null'.create(function create(o: object | null): voidundefinedvar undefined); // Error Argument of type 'undefined' is not assignable to parameter of type 'object | null'.2345Argument of type 'undefined' is not assignable to parameter of type 'object | null'.
Type assertions
Sometimes you’ll end up in a situation where you’ll know more about a value than TypeScript does. Usually 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 I’m doing.” A 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. One is the “angle-bracket” syntax:
tslet someValue:let someValue: any any = "this is a string"; let strLength:let strLength: number number = (<string>someValue)let someValue: any.length;(property) String.length: number
And the other is the as
-syntax:
tslet someValue:let someValue: any any = "this is a string"; let strLength:let strLength: number number = (someValue let someValue: anyas string).length;(property) String.length: number
The two samples are equivalent.
Using one over the other is mostly a choice of preference; however, when using TypeScript with JSX, only as
-style assertions are allowed.
A note about let
You may’ve noticed that so far, we’ve been using the let
keyword instead of JavaScript’s var
keyword which you might be more familiar with.
The let
keyword is actually a newer JavaScript construct that TypeScript makes available.
We’ll discuss the details later, but many common problems in JavaScript are alleviated by using let
, so you should use it instead of var
whenever possible.