TypeScript is an open-source programming language developed and maintained by Microsoft. It is a superset of JavaScript, which means that any valid JavaScript code is also valid TypeScript code. TypeScript extends JavaScript by adding static type definitions. Types provide a way to describe the shape of an object, providing better documentation, and allowing TypeScript to validate that your code is working correctly.
TypeScript is designed for the development of large applications and transcompiles to JavaScript. As applications grow in complexity, TypeScript's static typing can help developers detect and prevent many types of errors during the development process, improving the stability and maintainability of the code.
TypeScript offers several advantages over JavaScript:
- Type Safety: TypeScript provides a strict typing system, including both static and dynamic checking. This helps catch errors early in the development process, reducing runtime errors.
- Improved Tooling: Auto-completion, type checking, and source documentation are enhanced in TypeScript, making the development process smoother and faster.
- Better Collaboration: In large projects, TypeScript's type system can help ensure more predictable code and ease the collaboration between multiple developers.
- Future-Proof: TypeScript supports new JavaScript features, allowing developers to use the latest concepts without waiting for browser support. TypeScript then compiles these down to older, more compatible JavaScript versions.
While JavaScript is the most widely used scripting language for web development, TypeScript has gained popularity for its additional features that facilitate large-scale development. Here are some key differences:
- Static vs. Dynamic Typing: JavaScript is dynamically typed, meaning that variables can change types at runtime. TypeScript, being statically typed, requires type definitions at compile time, leading to more predictable code.
- TypeScript Features: TypeScript introduces features like interfaces, generics, and enums, which are not present in JavaScript.
- Compilation: TypeScript code is transcompiled into JavaScript code, which can then be run in any environment that supports JavaScript.
In summary, TypeScript enhances JavaScript with type definitions and new features, making it more robust for developing large applications. It strikes a balance between the dynamic flexibility of JavaScript and the rigorous structure needed for large-scale development.
Setting up a proper development environment is crucial for working efficiently with TypeScript. This section guides you through the process of installing TypeScript, configuring your Integrated Development Environment (IDE), and compiling your first TypeScript file.
To get started with TypeScript, you first need to install it. TypeScript requires Node.js as a prerequisite, so make sure you have Node.js installed on your machine. If you haven't installed Node.js yet, download and install it from nodejs.org.
Once Node.js is installed, you can install TypeScript globally using npm (Node Package Manager), which comes with Node.js. Open your terminal or command prompt and run the following command:
npm install -g typescript
This command installs the TypeScript compiler globally on your computer, making it accessible from any terminal or command prompt.
For a better development experience, it's recommended to use an Integrated Development Environment (IDE) or a code editor that supports TypeScript. Visual Studio Code (VS Code) is a popular choice among developers for TypeScript development due to its excellent TypeScript support.
To enhance your TypeScript development in VS Code, consider installing the following extensions:
- TypeScript TSLint Plugin for linting TypeScript code.
- Path Intellisense for auto-completing filenames.
- Prettier for auto-formatting your code.
To compile TypeScript code to JavaScript, you can use the TypeScript compiler (tsc
). Here's a simple example to get you started:
- Create a new file named
hello.ts
. - Add the following TypeScript code to the file:
let message: string = "Hello, TypeScript!";
console.log(message);
- Open your terminal or command prompt, navigate to the directory containing your
hello.ts
file, and compile the file with the following command:
tsc hello.ts
This command converts the hello.ts
TypeScript file into a hello.js
JavaScript file, which you can run using Node.js or in any JavaScript environment.
TypeScript enhances JavaScript by adding types. These types enable you to describe the shape of variables, function parameters, and objects, providing better documentation and allowing TypeScript to validate that your code is working as expected.
These are the basic types in TypeScript, similar to JavaScript.
- Number: All numbers in TypeScript are floating point values. These include integers, fractions, and exponentials.
- String: Textual data in TypeScript is represented using the
string
type. - Boolean: This type represents logical values:
true
andfalse
.
let age: number = 30;
let name: string = "John Doe";
let isStudent: boolean = false;
- Declare a variable
temperature
of typenumber
and assign it a value. - Create a variable
welcomeMessage
of typestring
that contains a greeting. - Make a variable
isLoggedIn
of typeboolean
to check if a user is logged in.
TypeScript allows you to work with arrays of values. You can specify the type of the array elements to ensure uniformity. Tuples are a TypeScript feature that allows you to create an array with fixed types and a fixed number of elements.
let list: number[] = [1, 2, 3];
let tuple: [string, number] = ["hello", 10]; // Tuple type
- Create an array
colors
of typestring[]
and initialize it with a few colors. - Define a tuple
userInfo
that contains astring
(for user name) and anumber
(for user age).
- Enum: A way to organize a collection of related values. Use enums to make your code more readable and less error-prone.
- Any: Use this type to bypass the type-checking system. Useful when you don't know the type of a variable because it's dynamic or comes from a third-party library.
- Void: A function that doesn't return a value returns
void
. - Null and Undefined: In TypeScript, both
null
andundefined
have their types namednull
andundefined
respectively.
enum Color {Red, Green, Blue};
let c: Color = Color.Green;
let notSure: any = 4;
notSure = "maybe a string instead";
function warnUser(): void {
console.log("This is a warning message");
}
let u: undefined = undefined;
let n: null = null;
- Define an enum
Season
with values forSpring
,Summer
,Autumn
, andWinter
. Use it in a variable declaration. - Create a function
logValue
that takes anany
type argument and logs it to the console. - Write a function
noReturn
that returnsvoid
and logs "No return" to the console.
TypeScript provides full support for JavaScript functions with added benefits of type checking and type annotations. Functions are the building blocks of readable, maintainable, and reusable code.
In TypeScript, you can specify the types of the function parameters and the return type of the function to ensure your functions are called with the correct types of arguments and return the correct type of result.
function add(x: number, y: number): number {
return x + y;
}
- Write a function
greet
that takes astring
as an argument and returns astring
with a greeting message. - Create a function
multiply
that takes twonumber
arguments and returns their product as anumber
.
TypeScript allows you to define functions with optional parameters and default parameters, enabling you to write more flexible and reusable code.
function buildName(firstName: string, lastName?: string): string {
if (lastName) return firstName + " " + lastName;
else return firstName;
}
function buildAddress(city: string, country = "USA"): string {
return city + ", " + country;
}
- Write a function
createEmail
with two parameters:to
(string) andsubject
(string, optional). Ifsubject
is not provided, it should default to "No Subject". - Modify the
add
function to include a third optional parameterz
of typenumber
. Ifz
is provided, add it to the result ofx
andy
.
Rest parameters allow you to work with an indefinite number of arguments as an array, providing the flexibility to handle multiple inputs more gracefully.
function getTotal(...numbers: number[]): number {
return numbers.reduce((accumulator, current) => accumulator + current, 0);
}
- Create a function
concatenateStrings
that takes a rest parameter of typestring[]
and returns all the strings concatenated together. - Implement a function
maxNumber
that takes a rest parameter of numbers and returns the maximum number from the list.
TypeScript's interfaces are a powerful way of defining contracts within your code as well as contracts with code outside of your project. Interfaces define the shape of objects, making it easier to manage and use complex data structures.
An interface in TypeScript is used to define the structure of an object. You can specify the types of various properties that the object can have.
interface Person {
firstName: string;
lastName: string;
age?: number; // Optional property
}
function greet(person: Person) {
console.log("Hello, " + person.firstName + " " + person.lastName);
}
- Define an interface
Vehicle
with propertiesmake
,model
, and an optional propertyyear
. - Write a function
createVehicle
that takes an object of typeVehicle
as an argument and returns it.
Interfaces can have optional properties, marked with a ?
. This means that objects of the interface can have these properties omitted.
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): { color: string; width: number } {
let newSquare = {color: "white", width: 100};
if (config.color) {
newSquare.color = config.color;
}
if (config.width) {
newSquare.width = config.width;
}
return newSquare;
}
- Extend the
Person
interface to include an optional propertyemail
. - Implement a function
updatePerson
that takes aPerson
object and an object with updates to some of the person's properties. The function should return the updated person object.
TypeScript allows you to make properties in an interface readonly. This means that once a property is assigned a value, it cannot be changed.
interface Point {
readonly x: number;
readonly y: number;
}
let p1: Point = { x: 10, y: 20 };
// p1.x = 5; // error: cannot reassign a readonly property
- Create an interface
Circle
with readonly propertiescenterX
,centerY
, andradius
. - Write a function
moveCircle
that attempts to modify thecenterX
andcenterY
properties of aCircle
object. Observe the TypeScript error and then fix the code.
TypeScript enhances JavaScript's class syntax with features like types, modifiers (public, private, etc.), and interfaces for implementing strong typing within classes.
class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
- Extend the
Animal
class with aDog
class that overrides themove
method. - Create an instance of the
Dog
class and call itsmove
method.
class Person {
private name: string;
constructor(name: string) { this.name = name; }
}
- Try to access the
name
property from outside thePerson
class and observe the TypeScript error. - Add a public method to the
Person
class that returns thename
property.
Generics provide a way to create reusable components that work with any data type, not just one.
function identity<T>(arg: T): T {
return arg;
}
- Use the
identity
function with different types and observe the inferred return type. - Extend the
identity
function to log the type ofarg
usingtypeof
.
interface GenericIdentityFn<T> {
(arg: T): T;
}
- Implement the
GenericIdentityFn
interface with a function that returns its argument. - Create an interface
GenericArray
with a generic type that represents an array of that type.
Enums allow you to define a set of named constants, making your code more readable and maintainable.
enum Direction {
Up = 1,
Down,
Left,
Right,
}
- Create a numeric enum
Response
with valuesNo = 0
,Yes = 1
, and use it in a function.
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
- Define a string enum
Message
with valuesSuccess = "SUCCESS"
,Failure = "FAILURE"
and use it to return function results.
Advanced types in TypeScript include union types, intersection types, type guards, and type assertions, among others.
function padLeft(value: string, padding: string | number) {
// function body
}
- Use the
padLeft
function with both astring
and anumber
as thepadding
parameter.
interface BusinessPartner {
name: string;
credit: number;
}
interface Contact {
email: string;
phone: string;
}
type Customer = BusinessPartner & Contact;
- Create an object of type
Customer
and use it to call a function that requires aBusinessPartner
and aContact
.
Modules in TypeScript allow for the modularization of code, making it easier to organize, maintain, and reuse across different parts of your application or across projects.
// In file mathUtils.ts
export function add(x: number, y: number): number {
return x + y;
}
// In another file
import { add } from './mathUtils';
- Create a module
stringUtils
with a functioncapitalize
that takes astring
and returns it with the first letter capitalized. Import and use it in another file.
// In file greeter.ts
export default function greet(name: string): string {
return `Hello, ${name}!`;
}
// In another file
import greet from './greeter';
- Modify the
greeter
module to include a default export and a named export. Import and use both in another file.
Namespaces are a TypeScript feature that allows you to group related functionalities under a single name, helping you to avoid global namespace pollution and organize your code more effectively.
namespace Validation {
export interface StringValidator {
isValid(s: string): boolean;
}
}
- Define a namespace
Calculator
with a classBasicCalculator
and use it in another file without importing.
Decorators provide a way to add both annotations and a meta-programming syntax for class declarations and members. Decorators are a stage 2 proposal for JavaScript and are available as an experimental feature of TypeScript.
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
- Create a decorator
@logged
that logs whenever a new instance of a class is created.
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}
- Implement a method decorator
@format
that formats the return value ofgreet
method as uppercase.
TypeScript provides several utility types to facilitate common type transformations. These utilities help you manipulate types easily, making your code more flexible and robust.
interface Todo {
title: string;
description: string;
}
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>): Todo {
return { ...todo, ...fieldsToUpdate };
}
const todo1: Readonly<Todo> = {
title: "Delete inactive users",
description: "..."
};
// todo1.title = "Hello"; // Error: cannot reassign a readonly property
- Use the
Partial
utility type to write a function that updates only certain fields of aTodo
object. - Apply the
Readonly
utility type to make aUser
object that should not be modified after creation.
TypeScript's behavior can be customized through the tsconfig.json
file. This file specifies the root files and the compiler options required to compile the project.
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"strict": true,
"outDir": "./dist"
},
"include": [
"./src/**/*"
]
}
- Create a
tsconfig.json
file for a project that compiles TypeScript files from asrc
folder to adist
folder, targeting ES6.
{
"compilerOptions": {
"noImplicitAny": true,
"strictNullChecks": true
}
}
- Modify the
tsconfig.json
to enablestrictNullChecks
and observe how it affects the compilation of your code.
{
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"]
}
- Adjust the
include
andexclude
options in yourtsconfig.json
to specifically target the files you want to compile.
TypeScript integrates with many tools that help improve the development workflow, from linting to testing.
npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
- Set up ESLint in a TypeScript project and configure it to extend
@typescript-eslint/recommended
.
Most modern IDEs support debugging TypeScript directly, especially when source maps are enabled in the tsconfig.json
.
- Configure your IDE to debug a TypeScript file with source maps enabled.
TypeScript can work seamlessly with most JavaScript testing frameworks, such as Jest or Mocha.
npm install jest @types/jest ts-jest --save-dev
- Set up Jest in a TypeScript project and write a simple test for a TypeScript function.
Congratulations on completing this TypeScript guide! You've learned the essentials of TypeScript, from basic types and functions to advanced concepts like generics and decorators. Remember, the key to mastering TypeScript is practice and continuous learning.
Stay updated with TypeScript's latest features and improvements by following the TypeScript blog and GitHub releases page.