Learn TypeScript – Exploring all the features with examples

Learn typescript

Sharing is caring!

89 Views -

TypeScript has gained immense popularity in the development community as a powerful superset of JavaScript. With its static typing and modern features, it enables developers to build robust and scalable applications. In this article, we will delve into TypeScript tutorials, covering the latest version, and provide detailed explanations with relevant code examples.

  1. Setting Up a TypeScript Development Environment

To start with TypeScript, you need a development environment. We’ll guide you through the process of setting up TypeScript with popular code editors, such as Visual Studio Code or WebStorm. Additionally, we’ll cover the configuration options and introduce package managers like npm and yarn.

  1. Install Node.js and npm

Visit the official Node.js website (https://nodejs.org) and download the appropriate installer

To verify that Node.js and npm are installed correctly, open your terminal or command prompt and run the following commands.

node -v
npm -v
  1. Create a TypeScript Project

Create a new directory for your TypeScript project. Open your terminal or command prompt, navigate to the desired location, and run the following command.

mkdir my-typescript-project
cd my-typescript-project
  1. Initialize a TypeScript Project

To initialize a new TypeScript project, you need to create a package.json file. This file contains metadata about your project and its dependencies. Run the following command in your project directory.

npm init -y
  1. Install TypeScript

To install TypeScript as a development dependency, run the following command.

npm install typescript --save-dev
  1. Create a tsconfig.json File

Next, you need to create a tsconfig.json file in the root of your project directory. This file specifies the compiler options for TypeScript. Run the following command to generate a basic tsconfig.json file.

npx tsc --init
  1. Configure tsconfig.json

Open the tsconfig.json file in a text editor and modify the options according to your project requirements. You can specify the target ECMAScript version, module system, output directory, and more. Refer to the official TypeScript documentation for detailed explanations of each option.

  1. Create a TypeScript File

Now, create a new file with a .ts extension in your project directory. For example, index.ts. This will be your TypeScript source file where you can write TypeScript code.

  1. Compile TypeScript to JavaScript

To compile your TypeScript code to JavaScript, run the following command in your terminal or command prompt.

npx tsc

This command invokes the TypeScript compiler (tsc) and compiles your .ts files based on the tsconfig.json configuration.

After successful compilation, you will see the generated JavaScript file(s) in the output directory specified in your tsconfig.json file.

  1. TypeScript Basic Types and Variables

Understanding the basic types is crucial for TypeScript development. We’ll cover essential types such as string, number, boolean, array, tuple, enum, and any. Through examples, you’ll learn how to declare variables, perform type annotations, and leverage type inference to improve code quality and maintainability.

  • The number Type

The number type represents numeric values, including integers and floating-point numbers. Here’s an example

let age: number = 25;
let height: number = 175.5;
  • The string Type

The string type represents textual data enclosed in quotes (single or double). Here’s an example

let name: string = "John Doe";
let message: string = 'Hello, TypeScript!';

 

  • The boolean Type

The boolean type represents logical values, either true or false. Here’s an example

let isLogged: boolean = true;
let hasPermission: boolean = false;

 

  • The array Type

The array type allows you to store multiple values of the same type in an ordered sequence. You can declare arrays using the following syntax

let numbers: number[] = [1, 2, 3, 4, 5];
let fruits: string[] = ["apple", "banana", "orange"];

Alternatively, you can use the generic Array type:

let numbers: Array<number> = [1, 2, 3, 4, 5];
let fruits: Array<string> = ["apple", "banana", "orange"];

 

  • The tuple Type

A tuple type allows you to define an array with a fixed-length and specific types for each element. Here’s an example

let person: [string, number] = ["John Doe", 25];

 

  • The enum Type

An enum type is a way to define a set of named constants. It assigns labels to a set of numeric values. Here’s an example

enum Color {
  Red,
  Green,
  Blue,
}

let primaryColor: Color = Color.Red;

In this example, Color is an enum with three possible values: Red, Green, and Blue. The default values start from 0, but you can assign custom values to enum members.

  • The any Type

The any type is a dynamic type that allows variables to hold values of any type. It is useful when working with existing JavaScript code or when the type is not known in advance. However, it bypasses type-checking. Use it with caution

let data: any = "Hello";
data = 10;
data = true;

 

  1. TypeScript Functions and Classes

Explore TypeScript’s function capabilities, including parameter typing, return types, optional and default parameters, and function overloading. We’ll also cover arrow functions, callbacks, and asynchronous functions using promises and async/await. Moving on, you’ll learn how to define classes, inheritance, access modifiers, and implement interfaces.

  1. TypeScript Functions:

      a. Parameter Typing.

You can specify the types of function parameters to ensure type safety. Here’s an example.

function greet(name: string): void {
  console.log(`Hello, ${name}!`);
}

greet("John");

In this example, the name parameter is annotated with the string type. The void return type indicates that the function doesn’t return a value.

       b. Return Types.

You can also specify the return type of a function explicitly. Here’s an example.

function add(a: number, b: number): number {
  return a + b;
}

const result: number = add(3, 5);
console.log(result); // Output: 8

In this example, the add function takes two number parameters and returns their sum, which is also of type number.

c. Optional and Default Parameters

You can make function parameters optional or provide default values. Here’s an example

function greet(name: string, age?: number): void {
  console.log(`Hello, ${name}!`);
  if (age) {
    console.log(`You are ${age} years old.`);
  }
}

greet("John"); // Output: Hello, John!
greet("Jane", 25); // Output: Hello, Jane! You are 25 years old.

In this example, the age parameter is marked as optional with the ? symbol. If the age argument is not provided, the function still executes correctly.

     d. Function Overloading.

TypeScript supports function overloading, where a single function can have multiple signatures. Here’s an example.

function combine(a: string, b: string): string;
function combine(a: number, b: number): number;
function combine(a: any, b: any): any {
  return a + b;
}

const result1: string = combine("Hello", "World");
const result2: number = combine(3, 5);

In this example, the combine function is overloaded with two signatures one for string inputs and one for number inputs. The implementation uses the any type, but the return type is determined based on the provided arguments.

TypeScript Classes
a. Class Definitions

You can define classes in TypeScript using the class keyword. Here’s an example

class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
  }
}

const john = new Person("John", 25);
john.greet(); // Output: Hello, my name is John and I'm 25 years old.

In this example, we define a Person class with name and age properties. The constructor initializes these properties, and the greet method logs a greeting message.

b. Inheritance

You can achieve class inheritance in TypeScript using the extends keyword. Here’s an example

class Student extends Person {
  grade: number;

  constructor(name: string, age: number, grade: number) {
    super(name, age);
    this.grade = grade;
  }

  study() {
    console.log(`${this.name} is studying in grade ${this.grade}.`);
  }
}

const alice = new Student("Alice", 15, 9);
alice.greet(); // Output: Hello, my name is Alice and I'm 15 years old.
alice.study(); // Output: Alice is studying in grade 9.

In this example, the Student class extends the Person class. It adds a grade property, a custom constructor, and a study method.

c. Access Modifiers

TypeScript provides access modifiers (public, private, and protected) to control the visibility of class members. Here’s an example

class Car {
  private speed: number;

  constructor() {
    this.speed = 0;
  }

  accelerate() {
    this.speed += 10;
  }

  getSpeed() {
    return this.speed;
  }
}

const car = new Car();
car.accelerate();
console.log(car.getSpeed()); // Output: 10
console.log(car.speed); // Error: Property 'speed' is private.

In this example, the speed property is marked as private, making it accessible only within the class. The accelerate method and getSpeed method can access the speed property.

   d. Interfaces

Interfaces allow you to define contracts for classes, specifying the expected properties and methods. Here’s an example

interface Shape {
  calculateArea(): number;
}

class Rectangle implements Shape {
  width: number;
  height: number;

  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
  }

  calculateArea() {
    return this.width * this.height;
  }
}

const rectangle = new Rectangle(10, 5);
console.log(rectangle.calculateArea()); // Output: 50

In this example, the Shape interface defines a contract with the calculateArea method. The Rectangle class implements the Shape interface and provides the implementation for the calculateArea method.

 

  1. TypeScript Modules and Namespaces

Modularity is essential in modern JavaScript applications. We’ll delve into TypeScript’s module system, covering import/export statements, default exports, and named exports. Additionally, we’ll explore namespaces to organize your code and avoid naming collisions. We’ll demonstrate how to leverage modules and namespaces in real-world scenarios.

  1. Namespaces

Namespaces in TypeScript are used to encapsulate code and prevent naming conflicts. They provide a way to organize related code elements such as classes, interfaces, functions, and variables within a container. Here’s an example

namespace MyNamespace {
  export interface Person {
    name: string;
    age: number;
  }

  export function greet(person: Person) {
    console.log(`Hello, ${person.name}! You are ${person.age} years old.`);
  }
}

const person: MyNamespace.Person = { name: "John", age: 25 };
MyNamespace.greet(person); // Output: Hello, John! You are 25 years old.

In this example, we define a namespace called MyNamespace. It contains an interface Person and a function greet. The export keyword is used to make these elements accessible outside the namespace.

To use the elements defined within the namespace, we access them using the namespace name followed by the element name, as shown in the code.

  1. Modules

Modules in TypeScript provide a more modern and widely used approach to organizing code. They allow you to split code into separate files, each representing a module that can be imported and used in other files. Here’s an example

// person.ts
export interface Person {
  name: string;
  age: number;
}

// greetings.ts
import { Person } from "./person";

export function greet(person: Person) {
  console.log(`Hello, ${person.name}! You are ${person.age} years old.`);
}

// main.ts
import { greet } from "./greetings";
import { Person } from "./person";

const person: Person = { name: "John", age: 25 };
greet(person); // Output: Hello, John! You are 25 years old.

In this example, we split the code into three separate files: person.ts, greetings.ts, and main.ts. The export keyword is used to make the Person interface and greet function accessible outside their respective files.

In main.ts, we import the greet function and Person interface from the other files using the import keyword. We can then use them as if they were defined locally.

Modules provide a more scalable and flexible way to organize code, especially in larger projects with multiple files and dependencies.

It’s worth noting that modules are the recommended approach for structuring code in TypeScript, and namespaces are more suitable for scenarios where legacy code or third-party libraries are involved.

 

  1. TypeScript Advanced Types

TypeScript offers powerful advanced types that enhance code flexibility and maintainability. We’ll cover union and intersection types, type guards, type aliases, type assertions, conditional types, and mapped types. With practical examples, you’ll learn how to utilize these advanced types effectively in your projects.

  1. Union Types

Union types allow you to define a type that can hold values of multiple types. You can use the | operator to separate the types. Here’s an example

function displayData(data: string | number) {
  console.log(data);
}

displayData("Hello"); // Output: Hello
displayData(42); // Output: 42

In this example, the displayData function can accept arguments of type string or number.

  1. Intersection Types

Intersection types allow you to combine multiple types into a single type. You can use the & operator to denote intersection. Here’s an example

interface Person {
  name: string;
}

interface Employee {
  empId: number;
}

type EmployeeWithPerson = Person & Employee;

const employee: EmployeeWithPerson = {
  name: "John Doe",
  empId: 12345,
};

In this example, we define two interfaces, Person and Employee, and then create an intersection type EmployeeWithPerson that combines the properties of both interfaces.

  1. Type Aliases:

Type aliases allow you to create custom names for types. They help improve code readability and allow you to reuse complex type definitions. Here’s an example

type Point = {
  x: number;
  y: number;
};

const origin: Point = { x: 0, y: 0 };

In this example, we create a type alias Point for an object with x and y properties. We then use the Point type alias to declare the origin variable.

  1. Type Guards

Type guards are used to narrow down the type of a variable within a conditional block. They help you perform type-specific operations based on runtime conditions. Here’s an example using the typeof type guard

function processData(data: string | number) {
  if (typeof data === "string") {
    console.log(data.toUpperCase());
  } else {
    console.log(data.toFixed(2));
  }
}

processData("hello"); // Output: HELLO
processData(3.14159); // Output: 3.14

In this example, the processData function checks the type of the data parameter using the typeof type guard. It performs different operations based on whether the type is a string or a number.

  1. Conditional Types

Conditional types allow you to create type transformations based on conditional logic. They enable you to define types that depend on other types. Here’s an example

type CheckType<T> = T extends string ? string : number;

const value1: CheckType<"Hello"> = "Hello"; // type is string
const value2: CheckType<42> = 42; // type is number

In this example, the CheckType conditional type checks if the generic type T is a string. If it is, the resulting type is a string; otherwise, it is a number.

  1. Mapped Types

Mapped types allow you to transform the properties of an existing type into a new type. You can modify, add, or remove properties based on certain rules. Here’s an example

type Person = {
  name: string;
  age: number;
};

type ReadonlyPerson = Readonly<Person>;

const person: ReadonlyPerson = { name: "John", age: 25 };
person.name = "Jane"; // Error: Cannot assign to 'name' because it is a read-only property.

In this example, we use the Readonly mapped type to create a new type ReadonlyPerson that makes all properties of Person read-only.

 

  1. TypeScript Decorators

Decorators allow you to add metadata and modify behavior at runtime. Decorators are declared using the @ symbol followed by the decorator function or expression. We’ll explain the concept of decorators and guide you through their usage in TypeScript. You’ll explore how to create decorators for class methods, properties, and class declarations, enabling you to implement powerful features like logging, caching, and validation.

  1. Class Decorators

Class decorators are applied to class declarations and can be used to modify or enhance the behavior of a class. Here’s an example

function Logger(target: Function) {
  console.log(`Logger invoked for class: ${target.name}`);
}

@Logger
class MyClass {
  // Class implementation...
}

In this example, the Logger decorator is applied to the MyClass class. When the code is executed, the decorator function is invoked, displaying a log message with the name of the class.

  1. Method Decorators

Method decorators are applied to methods within a class and allow you to modify or enhance the behavior of the method. Here’s an example

function Log(target: any, key: string, descriptor: PropertyDescriptor) {
  console.log(`Log invoked for method: ${key}`);
}

class MyClass {
  @Log
  myMethod() {
    // Method implementation...
  }
}

In this example, the Log decorator is applied to the myMethod method of the MyClass class. When the code is executed, the decorator function is invoked, displaying a log message with the name of the method.

  1. Property Decorators

Property decorators are applied to class properties and allow you to add metadata or modify the behavior of the property. Here’s an example

function ReadOnly(target: any, key: string) {
  const descriptor: PropertyDescriptor = {
    writable: false,
  };
  Object.defineProperty(target, key, descriptor);
}

class MyClass {
  @ReadOnly
  readonly myProperty: string;
}

In this example, the ReadOnly decorator is applied to the myProperty property of the MyClass class. The decorator modifies the property descriptor to make it read-only.

  1. Parameter Decorators

Parameter decorators are applied to the parameters of a method or constructor and allow you to modify or enhance the behavior of the parameter. Here’s an example

function LogParameter(target: any, key: string, index: number) {
  console.log(`LogParameter invoked for parameter at index ${index} of method: ${key}`);
}

class MyClass {
  myMethod(@LogParameter param: string) {
    // Method implementation...
  }
}

In this example, the LogParameter decorator is applied to the param parameter of the myMethod method. When the code is executed, the decorator function is invoked, displaying a log message with the index of the parameter and the name of the method.

Decorators can be combined and applied to the same element, allowing you to compose different behaviors or metadata for your classes, methods, properties, or parameters.

It’s important to note that decorators are experimental and subject to change. They require the experimentalDecorators flag to be enabled in your TypeScript configuration.

 

  1. TypeScript Tooling and Integration

Discover tools and frameworks that enhance TypeScript development, such as TypeScript Compiler (tsc), tsconfig.json, and popular frameworks like Angular, React, and Node.js. We’ll cover integration with build systems, linters, and testing frameworks, providing you with a seamless development experience.

  1. TypeScript Compiler (tsc)

The TypeScript Compiler (tsc) is the official TypeScript compiler that transforms TypeScript code into JavaScript. It supports various configuration options to customize the compilation process and produce output compatible with different JavaScript versions. The compiler can be used as a command-line tool or integrated into build systems.

  1. TypeScript Language Service

The TypeScript Language Service provides advanced features such as intelligent code completion, error checking, and refactoring tools. Integrated development environments (IDEs) and code editors can leverage the Language Service to enhance the developer experience. Editors like Visual Studio Code have built-in TypeScript support and provide real-time error checking, auto-completion, and other productivity features.

  1. TypeScript Declaration Files (typings)

Declaration files (.d.ts) provide type information for JavaScript libraries and frameworks that do not have native TypeScript support. They allow TypeScript to understand the types and APIs of these libraries, enabling better autocompletion and type checking. The DefinitelyTyped project hosts a vast collection of community-maintained declaration files for popular JavaScript libraries.

  1. TypeScript ESLint and TSLint

ESLint and TSLint are popular linting tools that help enforce coding standards and identify potential issues in TypeScript code. ESLint has extensive TypeScript support with the help of plugins like @typescript-eslint/parser and @typescript-eslint/eslint-plugin. TSLint, although deprecated, is still used in existing projects and provides a wide range of linting rules specifically designed for TypeScript.

  1. TypeScript Prettier

Prettier is a code formatter that enforces a consistent code style across the project. It supports TypeScript out of the box and can be easily integrated into the development workflow. Prettier can be configured to automatically format code on save or through build pipelines, ensuring a consistent code style across the team.

  1. TypeScript Build Tools and Task Runners

Various build tools and task runners can be used to automate TypeScript builds and streamline the development process. Tools like Webpack, Rollup, and Parcel provide bundling capabilities and optimize the output for production. Task runners like Gulp and Grunt offer flexibility to define custom build workflows and automate repetitive tasks.

  1. TypeScript Integration with Frameworks and Libraries

TypeScript has excellent integration with popular frameworks and libraries. Frameworks like Angular, React, and Vue have official TypeScript support, allowing you to write type-safe code and benefit from enhanced tooling features. Many other libraries and frameworks also provide TypeScript typings or declaration files, enabling seamless integration and improved development experience.

 

Conclusion

TypeScript offers a vast array of features and capabilities that enable developers to write maintainable, scalable, and error-free JavaScript applications. In this article, we’ve explored various TypeScript tutorials, covering the latest version, and provided detailed explanations with practical examples. By mastering TypeScript’s concepts and applying them to real-world scenarios, you’ll be well-equipped to build robust and efficient applications.

Remember, TypeScript is an evolving language, and staying up-to-date with the latest version and features is crucial. Always refer to the official TypeScript documentation and community resources for additional information and guidance on TypeScript development.

Happy coding with TypeScript!

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments