TypeScript
Learn to become a modern TypeScript developer by following the steps, skills, resources and guides listed in this pack.
1/ 93
TypeScript
TypeScript is a statically-typed programming language that is a superset of JavaScript. It was developed and is maintained by Microsoft. TypeScript was created to address the challenges of building large-scale JavaScript applications and adds optional type annotations, classes, interfaces, and other features to the language.
The main benefits of using TypeScript include:
Type Safety
Improved Tooling
Improved Maintainability
Backwards Compatibility
Learn more from the following links:
TypeScript
TypeScript is a statically-typed programming language that is a superset of JavaScript. It was developed and is maintained by Microsoft. TypeScript was created to address the challenges of building large-scale JavaScript applications and adds optional type annotations, classes, interfaces, and other features to the language.
The main benefits of using TypeScript include:
Type Safety
Improved Tooling
Improved Maintainability
Backwards Compatibility
Learn more from the following links:
1/93
TypeScript vs JavaScript
TypeScript is a superset of JavaScript that adds optional type annotations and other features such as interfaces, classes, and namespaces. JavaScript is a dynamically-typed language that is primarily used for client-side web development and can also be used for server-side development.
Here are a few key differences between TypeScript and JavaScript:
Types: TypeScript has optional type annotations while JavaScript is dynamically-typed. This means that in TypeScript, you can specify the data type of variables, parameters, and return values, which can help catch type-related errors at compile-time.
Syntax: TypeScript extends JavaScript syntax with features like interfaces, classes, and namespaces. This provides a more robust and organized structure for large-scale projects.
Tooling: TypeScript has better tooling support, such as better editor integration, type checking, and code refactoring.
Backwards Compatibility: TypeScript is fully compatible with existing JavaScript code, which means you can use TypeScript in any JavaScript environment.
Learn more from the following links:
2/93
TS/JS Interoperability
TypeScript and JavaScript have full interoperability, meaning you can use TypeScript code in JavaScript projects and vice versa. TypeScript is a superset of JavaScript, which means that any valid JavaScript code is also valid TypeScript code.
You can use JavaScript libraries in TypeScript projects by either including the JavaScript files directly or using type definitions for the library. Type definitions provide type information for JavaScript libraries, making it easier to use them in TypeScript.
On the other hand, you can use TypeScript code in JavaScript projects by simply compiling the TypeScript code into JavaScript. The generated JavaScript code can be used in any JavaScript environment, and it will work the same way as regular JavaScript code.
TypeScript’s compiler also supports type checking for plain JavaScript code by adding the
// @ts-check
comment at the top of a file. This allows the compiler to validate types by inspecting the JSDoc comments:3/93
Install and Configure
To install and configure TypeScript in your project, you need to perform the following steps:
Initialize npm in your project directory by running the following command:
4/93
tsconfig.json
tsconfig.json is a configuration file in TypeScript that specifies the compiler options for building your project. It helps the TypeScript compiler understand the structure of your project and how it should be compiled to JavaScript. Some common options include:
target
: the version of JavaScript to compile to.
module
: the module system to use.
strict
: enables/disables strict type checking.
outDir
: the directory to output the compiled JavaScript files.
rootDir
: the root directory of the TypeScript files.
include
: an array of file/directory patterns to include in the compilation.
exclude
: an array of file/directory patterns to exclude from the compilation.
Given below is the sample tsconfig.json
file:5/93
Compiler Options
TypeScript compiler accepts a number of command line options that allow you to customize the compilation process. These options can be passed to the compiler using the
--
prefix, for example:6/93
Running TypeScript
To run TypeScript code, you’ll need to have a TypeScript compiler installed. Here’s a general process to run TypeScript code:
Write TypeScript code in a
.ts
file (e.g. app.ts
)
Compile the TypeScript code into JavaScript using the TypeScript compiler:7/93
tsc
tsc
is the command line tool for the TypeScript compiler. It compiles TypeScript code into JavaScript code, making it compatible with the browser or any JavaScript runtime environment.
You can use the tsc
command to compile your TypeScript code by running the following command in your terminal or command prompt:8/93
ts-node
ts-node is a TypeScript execution and REPL for node.js, with source map and native ESM support. Learn more from the following links:
9/93
TS Playground
The TypeScript Playground is a great tool to learn TypeScript. It allows you to write TypeScript code and see the JavaScript output. It also allows you to share your code with others.
Learn more from the following links:
10/93
Typescript Types
TypeScript has several built-in types, including:
number
string
boolean
any
void
null and undefined
never
object
symbol
Enumerated types (enum)
Tuple types
Array types
Union types
Intersection types
Type aliases
Type assertions
You can also create custom types in TypeScript using interfaces, classes, and type aliases.
Learn more from the following links:
11/93
boolean
boolean
is a primitive data type in TypeScript that represents a boolean value i.e. either true or false. Given below is an example of a boolean variable declaration:12/93
number
It is a primitive data type in TypeScript that represents numeric values. It includes both integer and floating-point values.
13/93
string
It is a primitive data type in TypeScript that represents textual data. It is a set of elements of the 16-bit Unicode character set.
14/93
void
void
represents the return value of functions which don’t return a value. It’s the inferred type any time a function doesn’t have any return
statements, or doesn’t return any explicit value from those return statements:15/93
undefined
JavaScript has two primitive values used to signal absent or uninitialized value:
null
(absent) and undefined
(uninitialized).
TypeScript has two corresponding types by the same names. How these types behave depends on whether you have the strictNullChecks
option on.
With strictNullChecks
off, values that might be null
or undefined
can still be accessed normally, and the values null
and undefined
can be assigned to a property of any type. This is similar to how languages without null
checks (e.g. C#, Java) behave. The lack of checking for these values tends to be a major source of bugs; TypeScript always recommend people turn strictNullChecks
on if it’s practical to do so in the codebase.
With strictNullChecks
on, when a value is null
or undefined
, you will need to test for those values before using methods or properties on that value. Just like checking for undefined
before using an optional property, we can use narrowing to check for values that might be null
:16/93
null
JavaScript has two primitive values used to signal absent or uninitialized value:
null
(absent) and undefined
(unintialized).
TypeScript has two corresponding types by the same names. How these types behave depends on whether you have the strictNullChecks
option on.
With strictNullChecks
off, values that might be null
or undefined
can still be accessed normally, and the values null
and undefined
can be assigned to a property of any type. This is similar to how languages without null
checks (e.g. C#, Java) behave. The lack of checking for these values tends to be a major source of bugs; TypeScript always recommend people turn strictNullChecks
on if it’s practical to do so in the codebase.
With strictNullChecks
on, when a value is null
or undefined
, you will need to test for those values before using methods or properties on that value. Just like checking for undefined
before using an optional property, we can use narrowing to check for values that might be null
:17/93
Interface
TypeScript allows you to specifically type an object using an interface that can be reused by multiple objects.
18/93
Class
In TypeScript, a class is a blueprint for creating objects with specific properties and methods. Classes are a fundamental concept in object-oriented programming. Here is an example of a simple class in TypeScript:
19/93
Enum
Enums is not a type-level extension of JavaScript. It allows a developer to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases. TypeScript provides both numeric and string-based enums.
Here is an example of a numeric enum in TypeScript:
20/93
Array
To specify the type of an array like
[1, 2, 3]
, you can use the syntax number[]
; this syntax works for any type (e.g. string[]
is an array of strings, and so on). You may also see this written as Array<number>
, which means the same thing.21/93
Tuple
A tuple type is another sort of Array type that knows exactly how many elements it contains, and exactly which types it contains at specific positions.
22/93
Object
To define an
object
type, we simply list its properties and their types.
For example, here’s a function that takes a point-like object:23/93
Unknown
unknown
is the type-safe counterpart of any. Anything is assignable to unknown
, but unknown
isn’t assignable to anything but itself and any
without a type assertion or a control flow based narrowing. Likewise, no operations are permitted on an unknown
without first asserting or narrowing to a more specific type.24/93
Any
TypeScript has a special type,
any
, that you can use whenever you don’t want a particular value to cause typechecking errors.
When a value is of type any
, you can access any properties of it (which will in turn be of type any
), call it like a function, assign it to (or from) a value of any type, or pretty much anything else that’s syntactically legal:25/93
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
.
Examples of functions returning never:26/93
As Const
as const
is a type assertion in TypeScript that allows you to assert that an expression has a specific type, and that its value should be treated as a read-only value.
For example:27/93
As Type
In TypeScript, the as keyword is used for type assertions, allowing you to explicitly inform the compiler about the type of a value when it cannot be inferred automatically. Type assertions are a way to override the default static type-checking behavior and tell the compiler that you know more about the type of a particular expression than it does.
Here’s a simple example:
28/93
As Any
any
is a special type in TypeScript that represents a value of any type. When a value is declared with the any type, the compiler will not perform any type checks or type inference on that value.
For example:29/93
Non Null Assertion
The non-null assertion operator (!) is a type assertion in TypeScript that allows you to tell the compiler that a value will never be null or undefined.
30/93
satisfies Keyword
The
satisfies
operator lets us validate that the type of an expression matches some type, without changing the resulting type of that expression.
Learn more from the following resources:
31/93
Type Inference
Type inference in TypeScript refers to the process of automatically determining the type of a variable based on the value assigned to it. This allows you to write code that is more concise and easier to understand, as the TypeScript compiler can deduce the types of variables without you having to explicitly specify them.
Here’s an example of type inference in TypeScript:
32/93
Type Compatibility
TypeScript uses structural typing to determine type compatibility. This means that two types are considered compatible if they have the same structure, regardless of their names.
Here’s an example of type compatibility in TypeScript:
33/93
Combining Types
In TypeScript, you can combine types using type union and type intersection.
The union operator
|
is used to combine two or more types into a single type that represents all the possible types. For example:34/93
Union Types
Union Types in TypeScript allow you to specify multiple possible types for a single variable or parameter. A union type is written as a vertical bar
|
separated list of types.
For example, consider a function that takes either a string or a number as an argument:35/93
Intersection Types
An intersection type creates a new type by combining multiple existing types. The new type has all features of the existing types.
To combine types, you use the
&
operator as follows:36/93
Type Aliases
A Type Alias in TypeScript allows you to create a new name for a type.
Here’s an example:
37/93
keyof Operator
The
keyof
operator in TypeScript is used to get the union of keys from an object type. Here’s an example of how it can be used:38/93
Type Guards
Type guards are a way to narrow down the type of a variable. This is useful when you want to do something different depending on the type of a variable.
Learn more from the following resources:
39/93
instanceof operator
The
instanceof
operator is a way to narrow down the type of a variable. It is used to check if an object is an instance of a class.40/93
typeof Operator
The
typeof
operator is used to check the type of a variable. It returns a string value representing the type of the variable.41/93
Equality
TypeScript also uses switch statements and equality checks like
===
, !==
, ==
, and !=
to narrow types. For example:42/93
Truthiness
Truthiness might not be a word you’ll find in the dictionary, but it’s very much something you’ll hear about in JavaScript.
In JavaScript, we can use any expression in conditionals,
&&
s, ||
s, if
statements, Boolean negations (!
), and more. As an example, if statements don’t expect their condition to always have the type boolean.43/93
Type Predicates
Type predicates are functions that return a boolean value. They are used to narrow the type of a variable. Type predicates are used in type guards.
44/93
Functions
Functions are a core building block in TypeScript. Functions allow you to wrap a piece of code and reuse it multiple times. Functions in TypeScript can be either declared using function declaration syntax or function expression syntax.
Function Declaration Syntax:
45/93
Typing Functions
In TypeScript, functions can be typed in a few different ways to indicate the input parameters and return type of the function.
Function declaration with types:
46/93
Function Overloading
Function Overloading in TypeScript allows multiple functions with the same name but with different parameters to be defined. The correct function to call is determined based on the number, type, and order of the arguments passed to the function at runtime.
47/93
Interfaces
Interfaces in TypeScript provide a way to define a contract for a type, which includes a set of properties, methods, and events. It’s used to enforce a structure for an object, class, or function argument. Interfaces are not transpiled to JavaScript and are only used by TypeScript at compile-time for type-checking purposes.
Here’s an example of defining and using an interface in TypeScript:
48/93
Types vs Interfaces
In TypeScript, both types and interfaces can be used to define the structure of objects and enforce type checks. However, there are some differences between the two.
Types are used to create a new named type based on an existing type or to combine existing types into a new type. They can be created using the type keyword. For example:
49/93
Extending Interfaces
In TypeScript, you can extend an interface by creating a new interface that inherits from the original interface using the “extends” keyword. The new interface can include additional properties, methods, or redefine the members of the original interface.
50/93
Interface Declaration
An
interface
in TypeScript is a blueprint for creating objects with specific structure. An interface
defines a set of properties, methods, and events that a class or object must implement. The interface is a contract between objects and classes and can be used to enforce a specific structure for objects in your code.
Here is an example of an interface declaration in TypeScript:51/93
Hybrid Types
In TypeScript, a hybrid type is a type that combines multiple types into a single type. The resulting type is considered a union of those types. This allows you to specify that a value can have multiple types, rather than just one.
For example, you can create a hybrid type that can accept either a string or a number:
52/93
Classes
Classes in TypeScript are a blueprint for creating objects (instances of a class), providing a way to structure objects and encapsulate data and behavior. Classes in TypeScript have a similar syntax to classes in other object-oriented programming languages, such as Java and C#.
A class in TypeScript is defined using the class keyword, followed by the name of the class. The class definition can include fields (also known as properties or attributes), methods (functions), and a constructor.
53/93
Constructor Params
In TypeScript, constructor parameters can be declared with access modifiers (e.g.
public
, private
, protected
) and/or type annotations. The parameters are then automatically assigned to properties of the same name within the constructor, and can be accessed within the class. For example:54/93
Constructor Overloading
In TypeScript, you can achieve constructor overloading by using multiple constructor definitions with different parameter lists in a single class. Given below is the example where we have multiple definitions for the constructor:
55/93
Access Modifiers
In TypeScript, access modifiers are keywords used to control the visibility and accessibility of class properties and methods. There are three access modifiers in TypeScript:
public:
This is the default access modifier. Properties and methods declared as public can be accessed from anywhere, both inside and outside the class.
private:
Properties and methods declared as private can only be accessed within the same class. They are not accessible from outside the class.
protected:
Properties and methods declared as protected can be accessed within the class and its subclasses. They are not accessible from outside the class and its subclasses.
Access modifiers in TypeScript allow you to define the level of visibility and accessibility of properties and methods in your class, making your code more maintainable and secure.
Learn more from the following resources:
56/93
Abstract Classes
Abstract classes in TypeScript are classes that cannot be instantiated on their own and must be subclassed by other classes. Abstract classes provide a blueprint for other classes and can have abstract methods, which are methods without a body and must be overridden by the subclass. These classes are useful for defining a common interface or basic functionality that other classes can inherit and build upon.
57/93
Inheritance vs Polymorphism
Inheritance and polymorphism are two fundamental concepts in object-oriented programming, and they are supported in TypeScript as well.
Inheritance refers to a mechanism where a subclass inherits properties and methods from its parent class. This allows a subclass to reuse the code and behavior of its parent class while also adding or modifying its own behavior. In TypeScript, inheritance is achieved using the extends keyword.
Polymorphism refers to the ability of an object to take on many forms. This allows objects of different classes to be treated as objects of a common class, as long as they share a common interface or inheritance hierarchy. In TypeScript, polymorphism is achieved through method overriding and method overloading.
58/93
Method Overriding
In TypeScript, method overriding is a mechanism where a subclass provides a new implementation for a method that is already defined in its parent class. This allows the subclass to inherit the behavior of the parent class, but change its behavior to fit its own needs.
To override a method in TypeScript the signature of the method in the subclass must match exactly with the signature of the method in the parent class.
59/93
Generics
Generics in TypeScript are a way to write code that can work with multiple data types, instead of being limited to a single data type. Generics allow you to write functions, classes, and interfaces that take one or more type parameters, which act as placeholders for the actual data types that will be used when the function, class, or interface is used.
For example, the following is a generic function that takes a single argument of any data type and returns the same data type:
60/93
Generic Types
Generic types in TypeScript allow you to write objects, functions and classes that work with multiple data types, instead of being limited to a single data type. A generic type is defined using angle brackets
<T>
and can be used as a placeholder for a specific data type. The actual data type is specified when the function or class is used.
For example, the following is a generic function that takes a single argument of any data type and returns the same data type:61/93
Generic Constraints
Generic constraints in TypeScript allow you to specify the requirements for the type parameters used in a generic type. These constraints ensure that the type parameter used in a generic type meets certain requirements.
Constraints are specified using the
extends
keyword, followed by the type that the type parameter must extend or implement.62/93
Decorators
Decorators are a feature of TypeScript that allow you to modify the behavior of a class, property, method, or parameter. They are a way to add additional functionality to existing code, and they can be used for a wide range of tasks, including logging, performance optimization, and validation.
Here’s an example of how you might use a decorator in TypeScript:
63/93
Utility Types
TypeScript provides several utility types that can be used to manipulate and transform existing types. Here are some of the most common ones:
Partial
: makes all properties of a type optional.
Readonly
: makes all properties of a type read-only.
Pick
: allows you to pick specific properties from a type.
Omit
: allows you to omit specific properties from a type.
Exclude
: creates a type that is the set difference of A and B.
..and more.
Learn more from the following links:
64/93
Partial
The Partial type in TypeScript allows you to make all properties of a type optional. This is useful when you need to create an object with only a subset of the properties of an existing type.
Here’s an example of using the Partial type in TypeScript:
65/93
Pick
Pick constructs a type by picking the set of properties Keys (string literal or union of string literals) from Type.
66/93
Omit
Omit constructs a type by picking all properties from Type and then removing Keys (string literal or union of string literals).
67/93
Readonly
Readonly constructs a type with all properties of Type set to readonly, meaning the properties of the constructed type cannot be reassigned.
68/93
Record
Record constructs an object type whose property keys are Keys and whose property values are Type. This utility can be used to map the properties of a type to another type.
69/93
Exclude
Exclude constructs a type by excluding from UnionType all union members that are assignable to ExcludedMembers.
70/93
Extract
Extract constructs a type by extracting from Type all union members that are assignable to Union.
71/93
Non Nullable
Non-Nullable constructs a type by excluding
null
and undefined
from Type.72/93
Parameters
Parameters constructs a tuple type from the types used in the parameters of a function type Type.
73/93
ReturnType
Return type constructs a type consisting of the return type of function Type.
74/93
InstanceType
This type constructs a type consisting of the instance type of a constructor function in Type.
75/93
Awaited
This type is meant to model operations like await in async functions, or the
.then()
method on Promises - specifically, the way that they recursively unwrap Promises.76/93
Advanced Types
Advanced types in TypeScript are a set of advanced type constructs that allow for more complex and expressive type systems. Some of the most commonly used advanced types in TypeScript include:
Intersection Types
Union Types
Type Aliases
Conditional Types
Index Types
Mapped Types
Type Guards
These advanced types allow for more complex and expressive type systems, and enable you to write code that is safer, more maintainable, and easier to understand. By leveraging these advanced types, you can write code that is more robust, less prone to errors, and easier to maintain.
Learn more from the following links:
77/93
Mapped Types
Mapped types in TypeScript are a way to create a new type based on an existing type, where each property of the existing type is transformed in some way. Mapped types are declared using a combination of the
keyof
operator and a type that maps each property of the existing type to a new property type.
For example, the following is a mapped type that takes an object type and creates a new type with all properties of the original type but with their type changed to readonly
:78/93
Conditional Types
Conditional types in TypeScript are a way to select a type based on a condition. They allow you to write a type that dynamically chooses a type based on the types of its inputs. Conditional types are declared using a combination of the
infer
keyword and a type that tests a condition and selects a type based on the result of the test.
For example, the following is a conditional type that takes two types and returns the type of the first argument if it extends the second argument, and the type of the second argument otherwise:79/93
Literal Types
Literal types in TypeScript are a way to specify a value exactly, rather than just a type. Literal types can be used to enforce that a value must be of a specific type and a specific value. Literal types are created by using a literal value, such as a string, number, or boolean, as a type.
For example, the following is a literal type that represents a value of 42:
80/93
Template Literal Types
Template literal types in TypeScript are a way to manipulate string values as types. They allow you to create a type based on the result of string manipulation or concatenation. Template literal types are created using the backtick (“) character and string manipulation expressions within the type.
For example, the following is a template literal type that concatenates two strings:
81/93
Recursive Types
Recursive types in TypeScript are a way to define a type that references itself. Recursive types are used to define complex data structures, such as trees or linked lists, where a value can contain one or more values of the same type.
For example, the following is a recursive type that represents a linked list:
82/93
Modules
In TypeScript, modules are used to organize and reuse code. There are two types of modules in TypeScript:
Internal
External
Internal modules are used to organize code within a file and are also referred to as namespaces. They are defined using the “namespace” keyword.
External modules are used to organize code across multiple files. They are defined using the “export” keyword in one file and the “import” keyword in another file. External modules in TypeScript follow the CommonJS or ES modules standards.
Here is an example of how you can use internal modules in TypeScript:
83/93
Namespaces
In TypeScript, namespaces are used to organize and share code across multiple files. Namespaces allow you to group related functionality into a single unit and prevent naming conflicts.
Here’s an example of how you can use namespaces in TypeScript:
84/93
Ambient Modules
Ambient modules in TypeScript are used to declare external modules or third-party libraries in a TypeScript program. Ambient modules provide type information for modules that have no TypeScript declarations, but are available in the global scope.
Here’s an example of how you can use ambient modules in TypeScript:
85/93
External Modules
In TypeScript, external modules allow you to organize and share code across multiple files. External modules in TypeScript follow the CommonJS or ES modules standards.
Here’s an example of how you can use external modules in TypeScript:
86/93
Namespace Augmentation
In TypeScript, namespace augmentation is a way to extend or modify existing namespaces. This is useful when you want to add new functionality to existing namespaces or to fix missing or incorrect declarations in third-party libraries.
Here’s an example of how you can use namespace augmentation in TypeScript:
87/93
Global Augmentation
In TypeScript, global augmentation is a way to add declarations to the global scope. This is useful when you want to add new functionality to existing libraries or to augment the built-in types in TypeScript.
Here’s an example of how you can use global augmentation in TypeScript:
88/93
Ecosystem
Have a look at the linked nodes for different tools and frameworks that you can use to build your projects.
89/93
Formatting
Prettier is an opinionated code formatter with support for JavaScript, HTML, CSS, YAML, Markdown, GraphQL Schemas. By far the biggest reason for adopting Prettier is to stop all the on-going debates over styles. Biome is a faster alternative to Prettier! (It also does linting!)
Visit the following resources to learn more:
90/93
Linting
With ESLint you can impose the coding standard using a certain set of standalone rules.
Visit the following resources to learn more:
91/93
Useful Packages
TypeScript has a large ecosystem of packages that can be used to extend the language or to add functionality to your project. Here is the list of some of the most useful packages.
92/93
Build Tools
Task runners automatically execute commands and carry out processes behind the scenes. This helps automate your workflow by performing mundane, repetitive tasks that you would otherwise waste an egregious amount of time repeating yourself.
Common usages of task runners include numerous development tasks such as: spinning up development servers, compiling code (ex. SCSS to CSS), running linters, serving files up from a local port on your computer, and many more!
Visit the following resources to learn more:
93/93
Начать обучение
Создать ежедневную практику
СоздатьWitSlice © 2024