Software Engineer - Lindy.ai
The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.
TypeScript is an extension of the JavaScript language that uses JavaScript’s runtime with a compile-time type checker. This combination allows developers to use the full JavaScript ecosystem and language features, while also adding optional static type-checking, enum data types, classes, and interfaces. These features provide the developer with the flexibility of JavaScript’s dynamic nature, but also allow for a more reliable codebase, where type information can be used at compile-time to detect possible issues that could cause bugs or other unexpected behavior at runtime.
The extra type information also provides better documentation of codebases and improved IntelliSense (code completion, parameters info, and similar content assist features) in text editors. Teammates can identify exactly what types are expected for any variable or function parameter, without having to go through the implementation itself.
This tutorial will go through type declaration and all the basic types used in TypeScript. It will lead you through examples with different code samples, which you can follow along with in your own TypeScript environment or the TypeScript Playground, an online environment that allows you to write TypeScript directly in the browser.
To follow this tutorial, you will need:
tsc
) installed on your machine. To do this, refer to the official TypeScript website.All examples shown in this tutorial were created using TypeScript version 4.2.2.
When writing code in JavaScript, which is a purely dynamic language, you can’t specify the data types of variables. You create the variables and assign them a value, but do not specify a type, as shown in the following:
const language = {
name: "JavaScript"
};
In this code block, language
is an object that holds a string value for the property name
. The value type for language
and its properties is not explicitly set, and this could cause confusion later if future developers do not know what kind of value language
references.
TypeScript has as a main benefit a strict type system. A statically typed language is one where the type of the variables is known at compilation time. In this section, you will try out the syntax used to specify variable types with TypeScript.
Types are extra information that you write directly in your code. The TypeScript compiler uses this extra information to enforce the correct use of the different values depending on their type.
Imagine working with a dynamic language, such as JavaScript, and using a string
variable as if it were a number
. When you do not have strict
unit testing, the possible bug is only going to appear during runtime. If using the type system available with TypeScript, the compiler would not compile the code, giving an error instead, like this:
OutputThe right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. (2363)
To declare a variable with a certain type in TypeScript, use the following syntax:
declarationKeyword variableName: Type
declarationKeyword
would be something like let
, var
, or const
. This would be followed by the variable name, a colon (:
), and the type of that variable.
Any code you write in TypeScript is, in some way, already using the type system, even if you are not specifying any types. Take this code as an example:
let language = 'TypeScript';
In TypeScript, this has the same meaning as the following:
let language: string = 'TypeScript';
In the first example, you did not set the type of the language
variable to string
, but TypeScript inferred the type because you assigned a string value when it was declared. In the second example, you are explicitly setting the type of the language
variable to string
.
If you used const
instead of let
, it would be the following:
const language = 'TypeScript';
In this case, TypeScript would use the string literal TypeScript
as the type of your variable, as if you typed it this way:
const language: 'TypeScript' = 'TypeScript';
TypeScript does this because, when using const
, you are not going to assign a new value to the variable after the declaration, as doing this would raise an error.
Note: If you are using an editor that supports TypeScript, hovering over the variables with your cursor will display the type information of each variable.
If you explicitly set the type of a variable then use a different type as its value, the TypeScript Compiler (tsc
) or your editor will show the error 2322
. Try running the following:
const myNumber: number = 'look! this is not a number :)';
This will yield the following error:
OutputType 'string' is not assignable to type 'number'. (2322)
Now that you’ve tried out setting the type of a variable in TypeScript, the next section will show all the basic types supported by TypeScript.
TypeScript has multiple basic types that are used as building blocks when building more complex types. In the following sections, you are going to examine most of these types. Notice that most variables you are creating throughout this section could have their type omitted because TypeScript would be able to infer them, but you are being explicit about the types for learning purposes.
string
The type string
is used for textual data types, like string literals or template strings.
Try out the following code:
const language: string = 'TypeScript';
const message: string = `I'm programming in ${language}!`;
In this code block, both language
and message
are assigned the string
type. The template literal is still a string, even though it is determined dynamically.
Since strings are common in JavaScript programming, this is probably one of the types you are going to use most.
boolean
The type boolean
is used to represent true
or false
.
Try out the code in the following block:
const hasErrors: boolean = true;
const isValid: boolean = false;
Since hasErrors
and isValid
were declared as booleans, they can only be assigned the values true
and false
. Note that truthy and falsy values are not converted into their boolean equivalents and will throw an error if used with these variables.
number
The type number
is used to represent integers and floats, as in the following:
const pi: number = 3.14159;
const year: number = 2021;
This is another common type that is used often in JavaScript development, so this declaration will be common in TypeScript.
bigint
The type bigint
is a type that can be used when targeting ES2020. It’s used to represent BigInt
, which is a new datatype to store integers bigger than 2^53
.
Try the following code:
const bigNumber: bigint = 9007199254740993n;
Note: If this code throws an error, it is possible that TypeScript is not set up to target ES2020
. This can be changed in your tsconfig.json
file.
If you are working with numbers bigger than 2^53
or with some Math libraries, bigint
will be a common type declaration.
symbol
The symbol
type is used to represent the Symbol
primitive value. This will create a unique, unnamed value.
Run the following code using the Symbol()
constructor function:
const mySymbol: symbol = Symbol('unique-symbol-value');
The uniqueness of these values can be used to avoid reference collisions. For more on symbols in JavaScript, read the symbol article on Mozilla Developer Network (MDN).
In TypeScript, arrays are typed based on the elements they are expected to have. There are two ways to type an array:
[]
to the expected type of the array elements. For example, if you want to type an array that holds multiple number
values, you could do it like this:const primeNumbers: number[] = [2, 3, 5, 7, 11];
If you assigned a string value to this array, TypeScript would give you an error.
Array<T>
Generic, where T
is the expected type of the elements in that array. Using the previous example, it would become this:const primeNumbers: Array<number> = [2, 3, 5, 7, 11];
Both ways are identical, so pick one and try using only that format to represent arrays. This will keep the codebase consistent, which is often more important than choosing one style over the other.
One important aspect of using variables that hold arrays in TypeScript is that most of the time you will have to type them. Try the following code:
const myArray = [];
TypeScript is not able to infer the correct type expected by this array. Instead, it uses any[]
, which means an array of anything. This is not type-safe, and could cause confusion later in your code.
To make your code more robust, it is recommended to be explicit about the types of the array. For example, this would make sure the array has number elements:
const myArray: number[] = [];
This way, if you try to push an invalid value to the array, TypeScript will yield an error. Try out the following code:
const myArray: number[] = [];
myArray.push('some-text');
The TypeScript Compiler will show error 2345
:
OutputArgument of type 'string' is not assignable to parameter of type 'number'. (2345)
Tuples are arrays with a specific number of elements. One common use-case for this is storing 2D coordinates in the format [x, y]
. If you are working with React and using Hooks, the result from most Hooks is also a tuple, like const [isValid, setIsValid] = React.useState(false)
.
To type a tuple, as opposed to when typing an array, you wrap the type of the elements inside a []
, separating them with commas. Imagine you are creating a literal array with the types of the elements:
const position: [number, number] = [1, 2];
If you try to pass less, or more, than the number of elements that the tuple expects, the TypeScript Compiler is going to show the error 2322
.
Take the following code, for example:
const position: [number, number] = [1, 2, 3];
This would yield the following:
OutputType '[number, number, number]' is not assignable to type '[number, number]'.
Source has 3 element(s) but target allows only 2. (2322)
any
In certain situations it may be too hard to specify the types of a value, such as if that value is coming from a third-party library or from code that was initially written without TypeScript. This can be especially common when migrating a JavaScript codebase to TypeScript in small steps. In these scenarios, it is possible to use a special type called any
, which means any type. Using any
means opting-out of type checking, and is the same as making the TypeScript Compiler ignore that value.
Take the following code block:
let thisCanBeAnything: any = 12345;
thisCanBeAnything = "I can be anything - Look, I'm a string now";
thisCanBeAnything = ["Now I'm an array - This is almost like pure JavaScript!"];
None of these declarations will give an error in TypeScript, since the type was declared as any
.
Note: Most of the time, if you can, you should avoid using any
. Using this loses one of the main benefits of TypeScript: having statically typed code.
unknown
The unknown
type is like a type-safe counterpart of the any
type. You can use unknown
when you want to type something that you can not determine the value of, but still want to make sure that any code using that value is correctly checking the type before using it. This is useful for library authors with functions in their library that may accept a broad range of values from their users and do not want to type the value explicitly.
For example, if you have a variable called code
:
let code: unknown;
Then later in the program you can assign different values to that field, like 35
(number
), or completely unrelated values, like arrays or even objects.
Note: You are using let
because you are going to assign a new value to that variable.
Later in the same code, you could set code
to a number:
code = 35;
But then later you could assign it to an array:
code = [12345];
You could even re-assign it to an object:
code = {};
If later in the code you want to compare that value against some other number
, like:
const isCodeGreaterThan100 = code > 100;
The TypeScript compiler is going to display the error 2571
:
OutputObject is of type 'unknown'. (2571)
This happens because code
needs to be a number
type for this comparison, not an unknown
type. When doing any operation with a value of type unknown
, TypeScript needs to make sure that the type is the one it expects. One example of doing this is using the typeof
operator that already exists in JavaScript. Examine the following code block:
if (typeof code === 'number') {
const isCodeGreaterThan100 = code > 60;
// ...
} else {
throw new Error('Invalid value received as code');
}
In this example, you are checking if code
is a number using the typeof
operator. When you do that, TypeScript is going to coerce the type of your variable to number
inside that if
block, because at runtime the code inside the if
block is only going to be executed if code
is currently set to a number. Otherwise, you will throw a JavaScript error saying that the value passed is invalid.
To understand the differences between the unknown
and any
types, you can think of unknown
as “I do not know the type of that value” and any
as “I do not care what type this value holds”.
void
You can use the void
type to define the variable in question as holding no type at all. If you assign the result of a function that returns no value to a variable, that variable is going to have the type void
.
Take the following code:
function doSomething() {};
const resultOfVoidFunction: void = doSomething();
You will rarely have to use the void
type directly in TypeScript.
null
and undefined
null
and undefined
values in TypeScript have their own unique types that are called by the same name:
const someNullField: null = null;
const someUndefinedField: undefined = undefined;
These are especially useful when creating your own custom types, which will be covered later in this series.
never
The never
type is the type of a value that will never exist. For example, imagine you create a numeric variable:
const year: number = 2021;
If you create an if
block to run some code if year
is not a number
, it could be like the following:
if (typeof year !== "number") {
year;
}
The type of the variable year
inside that if
block is going to be never
. This is because, since year
is typed as number
, the condition for this if
block will never be met. You can think of the never
type as an impossible type because that variable can’t have a value at this point.
object
The object
type represents any type that is not a primitive type. This means that it is not one of the following types:
number
string
boolean
bigint
symbol
null
undefined
The object
type is commonly used to describe object literals because any object literal can be assigned to it:
const programmingLanguage: object = {
name: "TypeScript"
};
Note: There is a much better type than object
that could be used in this case called Record
. This has to do with creating custom types and is covered in a later tutorial in this series.
In this tutorial, you tried out the different basic types that are available in TypeScript. These types are going to be frequently used when working in a TypeScript codebase and are the main building blocks to create more complex, custom types.
For more tutorials on TypeScript, check out our How To Code in TypeScript series page.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
TypeScript is an extension of the JavaScript language that uses JavaScript’s runtime with a compile-time type checker. This combination allows developers to use the full JavaScript ecosystem and language features, while also adding optional static type-checking, enum data types, classes, and interfaces.
This series will show you the syntax you need to get started with TypeScript, allowing you to leverage its typing system to make scalable, enterprise-grade code.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!