Mastering TypeScript: A Comprehensive Guide
Sadanand gadwal
Posted on April 18, 2024
From Fundamentals to Intermediate Techniques for Effective Development
Beginner Level:
Understand JavaScript Fundamentals:
JavaScript fundamentals include knowledge of variables, data types, functions, objects, arrays, and control flow.
// Variables
let x = 5;
const y = "Hello";
// Data Types
let num = 10; // Number
let str = "Hello"; // String
let bool = true; // Boolean
let arr = [1, 2, 3]; // Array
let obj = { name: "sadanandgadwal", age: 23 }; // Object
// Functions
function greet(name) {
return "Hello, " + name + "!";
}
console.log(greet("sadanandgadwal")); // Output: Hello, sadanandgadwal!
// Objects
let person = {
name: "sadanandgadwal",
age: 23,
greet: function() {
return "Hello, " + this.name + "!";
}
};
console.log(person.greet()); // Output: Hello, sadanandgadwal!
Introduction to TypeScript:
TypeScript is a superset of JavaScript that adds optional static typing, interfaces, classes, and modules among other features.
// Define a function named greet that takes a parameter 'name' of type string and returns a string.
function greet(name: string): string {
return "Hello, " + name + "!";
}
// Call the greet function with the argument "sadanandgadwal" and log the returned value to the console.
console.log(greet("sadanandgadwal")); // Output: Hello, sadanandgadwal!
// Define an interface named Person which specifies that any object implementing it must have a 'name' property of type string and an 'age' property of type number.
interface Person {
name: string;
age: number;
}
// Define a function named greetPerson that takes a parameter 'person' of type Person interface and returns a string.
function greetPerson(person: Person): string {
return "Hello, " + person.name + "!";
}
// Call the greetPerson function with an object that satisfies the Person interface, and log the returned value to the console.
console.log(greetPerson({ name: "sadanandgadwal", age: 23 })); // Output: Hello, sadanandgadwal!
Setting Up Development Environment:
Setting up the development environment involves installing Node.js and npm and configuring a TypeScript compiler like tsc.
# Install Node.js and npm
# Download and install from https://nodejs.org/
# Install TypeScript globally
npm install -g typescript
# Create a TypeScript file (example.ts)
# Run the TypeScript compiler to generate JavaScript
tsc example.ts
Basic TypeScript Syntax:
Basic TypeScript syntax includes declaring variables with types, understanding type inference, and using basic type annotations and assertions.
// Variable Declaration
let x: number = 5; // Declare a variable 'x' of type number and assign it the value 5.
const y: string = "Hello"; // Declare a constant 'y' of type string and assign it the value "Hello".
// Type Inference
let num = 10; // TypeScript infers the type of 'num' as 'number' based on its initial value.
let str = "Hello"; // TypeScript infers the type of 'str' as 'string' based on its initial value.
// Basic Type Annotations and Assertions
let z: boolean; // Declare a variable 'z' of type boolean.
z = true; // Assign the value true to the variable 'z'.
// Type Assertion
let someValue: any = "this is a string"; // Declare a variable 'someValue' of type 'any' and assign it a string value.
let strLength: number = (someValue as string).length; // Assert that 'someValue' is of type string and then access its length property.
// Alternatively, you could use angle bracket syntax: let strLength: number = (<string>someValue).length;
console.log(x); // Output: 5
console.log(y); // Output: Hello
console.log(num); // Output: 10
console.log(str); // Output: Hello
console.log(z); // Output: true
console.log(strLength); // Output: 16
Functions and Interfaces:
In TypeScript, you can define function types and use interfaces to define object shapes and enforce contracts.
// Function Types
// Define a type alias named GreetFunction representing a function that takes a 'name' parameter of type 'string' and returns a 'string'.
type GreetFunction = (name: string) => string;
// Declare a variable 'greet' of type 'GreetFunction' and assign it a function expression that matches the defined function type.
let greet: GreetFunction = function(name: string) {
return "Hello, " + name + "!";
};
// Call the 'greet' function with the argument "sadanandgadwal" and log the returned value to the console.
console.log(greet("sadanandgadwal")); // Output: Hello, sadanandgadwal!
// Interface
// Define an interface named 'Person' with properties 'name' of type 'string' and 'age' of type 'number'.
interface Person {
name: string;
age: number;
}
// Define a function named 'greetPerson' that takes a parameter 'person' of type 'Person' interface and returns a 'string'.
function greetPerson(person: Person): string {
return "Hello, " + person.name + "!";
}
// Call the 'greetPerson' function with an object that satisfies the 'Person' interface, and log the returned value to the console.
console.log(greetPerson({ name: "sadanandgadwal", age: 23 })); // Output: Hello, sadanandgadwal!
Working withย Classes:
Classes and inheritance in TypeScript allow you to create blueprints for objects with methods and properties.
// Class
class Person {
// Define properties 'name' and 'age'.
name: string;
age: number;
// Define a constructor function that initializes 'name' and 'age' properties when a new object is created.
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// Define a method named 'greet' that returns a greeting message using the 'name' property.
greet(): string {
return "Hello, " + this.name + "!";
}
}
// Create a new instance of the 'Person' class with name "sadanandgadwal" and age 23.
let person = new Person("sadanandgadwal", 23);
// Call the 'greet' method of the 'person' object and log the returned value to the console.
console.log(person.greet()); // Output: Hello, sadanandgadwal!
Intermediate Level (Continued):
Advanced Types:
Advanced types in TypeScript include union types, intersection types, type aliases, conditional types, etc.
// Union Types
// Declare a variable 'val' that can hold values of type 'number' or 'string'.
let val: number | string;
val = 10; // Assign a number to 'val' (valid).
val = "Hello"; // Assign a string to 'val' (valid).
// val = true; // Error: Type 'boolean' is not assignable to type 'number | string'
// Intersection Types
// Define two interfaces 'A' and 'B' with different properties.
interface A {
propA: number;
}
interface B {
propB: string;
}
// Create a new type 'C' which is an intersection of types 'A' and 'B'.
type C = A & B;
// Declare a variable 'obj' of type 'C' and assign an object with properties from both interfaces.
let obj: C = { propA: 10, propB: "Hello" };
// Conditional Types
// Define a conditional type 'TypeName<T>' which returns different strings based on the type of 'T'.
type TypeName<T> = T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
"unknown";
// Declare variables of type 'TypeName' with different type arguments and assign them values.
let a: TypeName<string> = "string"; // Output: "string"
let b: TypeName<number> = "number"; // Output: "number"
let c: TypeName<boolean> = "boolean"; // Output: "boolean"
let d: TypeName<object> = "unknown"; // Output: "unknown"
console.log(val); // Output: Hello
console.log(obj); // Output: { propA: 10, propB: "Hello" }
console.log(a); // Output: string
console.log(b); // Output: number
console.log(c); // Output: boolean
console.log(d); // Output: unknown
Generics:
Generics allow you to write reusable, type-safe functions, interfaces, and classes.
// Generic Function
// Define a generic function 'identity' that takes an argument 'arg' of type 'T' and returns the same type 'T'.
function identity<T>(arg: T): T {
return arg;
}
// Call the 'identity' function with a number and assign the result to 'num'.
let num: number = identity(10); // Output: 10
// Call the 'identity' function with a string and assign the result to 'str'.
let str: string = identity("Hello"); // Output: "Hello"
// Generic Interface
// Define a generic interface 'Box<T>' with a single property 'value' of type 'T'.
interface Box<T> {
value: T;
}
// Create a variable 'box' of type 'Box<number>' and assign an object with a 'value' property of type number.
let box: Box<number> = { value: 10 };
// Generic Class
// Define a generic class 'Pair<T, U>' with two properties 'first' of type 'T' and 'second' of type 'U'.
class Pair<T, U> {
constructor(public first: T, public second: U) {}
}
// Create an instance 'pair' of the 'Pair<number, string>' class with values 10 and "Hello".
let pair: Pair<number, string> = new Pair(10, "Hello");
console.log(num); // Output: 10
console.log(str); // Output: Hello
console.log(box); // Output: { value: 10 }
console.log(pair); // Output: Pair { first: 10, second: "Hello" }
Modules and Namespaces:
Modules in TypeScript allow you to organize code into reusable units. Namespaces provide a way to logically group related code.
// math.ts
// Define a function 'sum' in the module 'math' that takes two numbers and returns their sum.
export function sum(a: number, b: number): number {
return a + b;
}
// app.ts
// Import the 'sum' function from the 'math' module.
import { sum } from "./math";
// Call the 'sum' function and log the result to the console.
console.log(sum(2, 3)); // Output: 5
// namespace
// Define a namespace 'Math' containing a function 'sum' that calculates the sum of two numbers.
namespace Math {
export function sum(a: number, b: number): number {
return a + b;
}
}
// app.ts
/// <reference path="math.ts" />
// Use the 'sum' function from the 'Math' namespace and log the result to the console.
console.log(Math.sum(2, 3)); // Output: 5
Decorators:
Decorators are a feature of TypeScript that allow you to attach metadata to classes, methods, and properties.
// Class Decorator
// Define a class decorator 'Logged' that takes a target function.
function Logged(target: Function) {
// Log a message indicating that the class has been logged.
console.log("Class logged:", target);
}
// Apply the 'Logged' decorator to the 'MyClass' class.
@Logged
class MyClass {}
// Method Decorator
// Define a method decorator 'Log' that takes target, key, and descriptor arguments.
function Log(target: any, key: string, descriptor: PropertyDescriptor) {
// Log a message indicating that the method has been logged.
console.log("Method logged:", key);
}
// Define a class 'MyService'.
class MyService {
// Apply the 'Log' decorator to the 'getData' method.
@Log
getData() {}
}
// Property Decorator
// Define a property decorator factory 'Configurable' that takes a boolean value.
function Configurable(value: boolean) {
return function(target: any, propertyKey: string) {
// Define the property with configurable set to the provided value.
Object.defineProperty(target, propertyKey, {
configurable: value
});
};
}
// Define a class 'MyComponent'.
class MyComponent {
// Apply the 'Configurable' decorator to the 'apiUrl' property with configurable set to false.
@Configurable(false)
apiUrl = "https://example.com";
}
// Console output
console.log(MyClass);
new MyService().getData();
console.log(Object.getOwnPropertyDescriptor(MyComponent.prototype, "apiUrl"));
Error Handling:
Understanding how TypeScript handles errors and exceptions, including synchronous and asynchronous error handling strategies.
// Synchronous Error Handling
// Define a function 'divide' that takes two numbers and returns the result of dividing the first number by the second number.
function divide(x: number, y: number): number {
// Check if the second number is zero.
if (y === 0) {
// If it is zero, throw an error with a message.
throw new Error("Division by zero");
}
// If the second number is not zero, perform the division and return the result.
return x / y;
}
// Use a try-catch block to handle errors that may occur during the execution of the 'divide' function.
try {
// Call the 'divide' function with arguments 10 and 0.
console.log(divide(10, 0)); // Output: Error: Division by zero
} catch (error) {
// If an error occurs, log the error message to the console.
console.error(error.message);
}
// Asynchronous Error Handling
// Define an asynchronous function 'fetchData' that fetches data from a remote URL.
async function fetchData() {
try {
// Attempt to fetch data from the specified URL.
let response = await fetch("https://example.com/data");
// Check if the response is OK.
if (!response.ok) {
// If the response is not OK, throw an error with a message.
throw new Error("Failed to fetch data");
}
// If the response is OK, parse the JSON data.
let data = await response.json();
// Log the parsed data to the console.
console.log(data);
} catch (error) {
// If an error occurs during the fetch operation or parsing, log the error message to the console.
console.error(error.message);
}
}
// Call the 'fetchData' function to initiate the asynchronous data fetching process.
fetchData();
Conclusion
This guide covered TypeScript essentials, from syntax to advanced features like generics and decorators. Error handling strategies and integration with frameworks were explored. Mastering TypeScript empowers developers to create scalable, organized codebases, contributing effectively to modern web development projects.
Playground for Typescript
Playcode.io is an online code editor and playground that allows users to write, edit, and execute HTML, CSS, and JavaScript code and even Typescript.
๐ Stay Connected! ๐
Hey there, awesome reader! ๐ Want to stay updated with my latest insights,Follow me on social media!
Posted on April 18, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.