Hello my fellow frontend, backend and fullstack developer, today i will be covering some beginner Typescript concepts with examples.
Let's get started...
1) Introduction to TypeScript
TypeScript is a superset of JavaScript that adds static typing to the language. It helps catch errors at compile time and provides better code organization.
function greet(name: string) {
return `Hello, ${name}!`;
}
console.log(greet("Alice"));
Tips and Tricks: Use TypeScript to define types for variables, functions, and more to improve code reliability.
Best Use Cases: Ideal for large-scale applications where type safety is crucial.
2) Basic Types
TypeScript includes basic types such as number, string, boolean, array, etc.
let age: number = 25;
let name: string = "Bob";
let isStudent: boolean = true;
let numbers: number[] = [1, 2, 3, 4, 5];
Tips and Tricks: Use type inference to let TypeScript automatically determine the type when possible.
Best Use Cases: Used for defining simple data types in your code.
3) Interfaces
Interfaces define the structure of an object in TypeScript.
interface Person {
name: string;
age: number;
}
function greet(person: Person) {
return `Hello, ${person.name}!`;
}
Tips and Tricks: Interfaces help enforce a consistent shape across objects.
Best Use Cases: Useful for defining data contracts in your application.
4) Classes
Classes in TypeScript allow you to use object-oriented programming concepts like inheritance and encapsulation.
class Animal {
constructor(public name: string) {}
move(distance: number) {
console.log(`${this.name} moved ${distance} meters.`);
}
}
Tips and Tricks: Use access modifiers like public, private, and protected for better encapsulation.
Best Use Cases: Great for modeling real-world entities in your code.
5) Generics
Generics allow you to create reusable components that can work with a variety of data types.
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("hello");
Tips and Tricks: Use generics when you want a function or class to work with any data type.
Best Use Cases: Helpful for creating flexible and reusable code.
6) Enums
Enums in TypeScript allow you to define a set of named constants.
enum Direction {
Up,
Down,
Left,
Right
}
let heading: Direction = Direction.Up;
Tips and Tricks: Enums help make your code more readable by giving friendly names to numeric values.
Best Use Cases: Useful when you have a set of related constants.
7) Type Assertion
Type assertion is a way to tell the compiler about the type of a variable when TypeScript can't infer it.
let input: any = "hello";
let length: number = (input as string).length;
Tips and Tricks: Use type assertion when you know more about a value than TypeScript does.
Best Use Cases: Helpful when working with data from external sources.
8) Decorators
Decorators are a special kind of declaration that can be attached to classes, methods, accessors, properties, or parameters.
function log(target: any, key: string) {
console.log(`Method ${key} called`);
}
class Example {
@log
someMethod() {
// Method implementation
}
}
Tips and Tricks: Decorators are widely used in frameworks like Angular for metadata reflection.
Best Use Cases: Useful for adding metadata to classes and members.
9) Modules
Modules in TypeScript help organize code into reusable units.
// math.ts
export function add(a: number, b: number): number {
return a + b;
}
// app.ts
import { add } from './math';
console.log(add(2, 3)); // Output: 5
Tips and Tricks: Use modules to keep your codebase clean and maintainable.
Best Use Cases: Essential for structuring large applications.
10) Namespaces
Namespaces allow you to organize code by grouping logically related objects.
namespace Geometry {
export class Circle {
// Circle implementation
}
}
let circle = new Geometry.Circle();
11) Type Inference
Type inference in TypeScript allows the compiler to determine types when they're not explicitly specified.
let num = 10; // TypeScript infers the type as number
Tips and Tricks: TypeScript's type inference can save time and make the code cleaner.
Best Use Cases: Useful for writing concise code without sacrificing type safety.
12) Type Guards
Type guards allow you to narrow down the type of a variable within a conditional block.
function isNumber(x: any): x is number {
return typeof x === "number";
}
if (isNumber(value)) {
// Inside this block, TypeScript knows 'value' is a number
}
Tips and Tricks: Type guards are helpful when dealing with union types.
Best Use Cases: Useful for working with complex or dynamic data types.
13) Union Types
Union types allow a variable to have multiple types.
let result: number | string;
result = 10; // Valid
result = "error"; // Also valid
Tips and Tricks: Use union types to handle different scenarios for a variable.
Best Use Cases: Great for representing diverse data types.
14) Intersection Types
Intersection types allow combining multiple types into one.
type A = { a: number };
type B = { b: string };
type C = A & B; // C has both a number property and a string property
Tips and Tricks: Intersection types are useful for combining different types for complex scenarios.
Best Use Cases: Helpful for creating complex data structures.
15) Type Aliases
Type aliases allow you to create a name for any data type.
type Age = number;
let userAge: Age = 25;
Tips and Tricks: Use type aliases to give descriptive names to complex types.
Best Use Cases: Useful for improving code readability and maintainability.
16) Triple-Slash Directives
Triple-slash directives are single-line comments containing a single XML tag.
/// <reference path="myModule.d.ts" />
Tips and Tricks: Triple-slash directives are often used to declare dependencies between files.
Best Use Cases: Useful when working with modules and declaration files.
17) Type Checking JavaScript Files
TypeScript can be used to check and type-check JavaScript files.
// @ts-check
let num: number = "not a number"; // TypeScript will throw a type error
Tips and Tricks: Type checking JavaScript files can catch bugs and improve code quality.
Best Use Cases: Useful for gradually migrating a JavaScript codebase to TypeScript.
18) Type Inference for Destructured Objects
TypeScript can infer types for destructured objects.
let person = { name: "Alice", age: 30 };
let { name, age } = person; // TypeScript infers the types of 'name' and 'age'
Tips and Tricks: Type inference for destructured objects can save time and reduce redundancy.
Best Use Cases: Helpful for working with complex data structures.
19) Conditional Types
Conditional types in TypeScript allow you to create types that depend on other types.
type NonNullable<T> = T extends null | undefined ? never : T;
type StringOrNumber = string | number;
type NonNullableStringOrNumber = NonNullable<StringOrNumber>; // Result: string | number
Tips and Tricks: Conditional types are powerful for creating flexible and conditional type definitions.
Best Use Cases: Useful for creating generic types that depend on conditions.
20) Mapped Types
Mapped types in TypeScript allow you to create new types from existing types.
type Flags = {
option1: boolean;
option2: boolean;
};
type NullableFlags = { [K in keyof Flags]: Flags[K] | null }; // Result: { option1: boolean | null, option2: boolean | null }
Tips and Tricks: Mapped types are useful for transforming existing types into new ones.
Best Use Cases: Helpful for creating variations of existing types.
21) Declaration Merging
Declaration merging in TypeScript allows combining multiple declarations for the same entity.
interface User {
name: string;
}
interface User {
age: number;
}
let newUser: User = { name: "Alice", age: 30 };
Tips and Tricks: Declaration merging is useful for extending existing types without modifying them directly.
Best Use Cases: Helpful for adding functionality to third-party libraries.
22) Type Guards with Classes
Type guards can also be used with classes to narrow down the type of an instance.
class Animal {
move() {
console.log("Moving...");
}
}
class Dog extends Animal {
bark() {
console.log("Woof!");
}
}
function isDog(animal: Animal): animal is Dog {
return (animal as Dog).bark !== undefined;
}
Tips and Tricks: Type guards with classes are useful for handling polymorphic behavior.
Best Use Cases: Great for dealing with inheritance and polymorphism.
23) Tuple Types
Tuple types in TypeScript allow expressing an array where the type of a fixed number of elements is known.
let coordinates: [number, number] = [10, 20];
Tips and Tricks: Use tuple types when working with fixed-length arrays with known element types.
Best Use Cases: Useful for representing structured data like coordinates, RGB values, etc.
24) Index Signatures
Index signatures allow defining how objects can be indexed.
interface StringArray {
[index: number]: string;
}
let myArray: StringArray = ["a", "b", "c"];
Tips and Tricks: Index signatures are useful for working with objects that behave like arrays.
Best Use Cases: Helpful for dealing with dynamic data structures.
25) Type Guards with typeof and instanceof
Type guards can be created using the typeof and instanceof operators.
function logValue(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase());
} else if (value instanceof Number) {
console.log(value.valueOf());
}
}
Tips and Tricks: Use typeof for primitive types and instanceof for checking instances of classes.
Best Use Cases: Useful for checking specific types in conditional blocks.
26) Recursive Types
TypeScript supports defining recursive types where a type refers to itself.
interface TreeNode {
value: string;
children: TreeNode[];
}
Tips and Tricks: Recursive types are useful for representing hierarchical data structures.
Best Use Cases: Great for modeling tree-like data.
27) String Literal Types
String literal types allow defining a type that can only have specific string values.
type Direction = "up" | "down" | "left" | "right";
let move: Direction = "up";
Tips and Tricks: String literal types help create specific and concise type definitions.
Best Use Cases: Useful for representing a fixed set of string values.
28) Namespace Merging
Namespace merging allows extending existing namespaces across multiple files.
// math.ts
namespace Math {
export function subtract(a: number, b: number): number {
return a - b;
}
}
// extendedMath.ts
namespace Math {
export function multiply(a: number, b: number): number {
return a * b;
}
}
Tips and Tricks: Namespace merging is useful for adding functionality to existing namespaces.
Best Use Cases: Helpful for modularizing code across multiple files.
29) Type Predicates
Type predicates are functions that return a type predicate to narrow down the type within a conditional block.
function isString(value: any): value is string {
return typeof value === "string";
}
if (isString(input)) {
console.log(input.toUpperCase());
}
Tips and Tricks: Type predicates are useful for creating reusable type narrowing functions.
Best Use Cases: Great for handling complex type checks.
30) Inference and Strict Mode
TypeScript's strict mode enables additional type checking options to catch more errors.
// @ts-check
let num: number = "not a number"; // TypeScript in strict mode will throw a type
31) Type Guards with in Operator
Type guards can also be created using the in operator to check for the existence of a property in an object.
function hasName(obj: any): obj is { name: string } {
return "name" in obj;
}
if (hasName(user)) {
console.log(user.name);
}
Tips and Tricks: The in operator is useful for checking the presence of properties dynamically.
Best Use Cases: Helpful for checking object properties in a type-safe manner.
32) Type Inference for Arrays
TypeScript can infer the type of arrays based on the elements assigned to them.
numbers = [1, 2, 3]; // TypeScript infers 'numbers' as number[]
Tips and Tricks: Type inference for arrays can simplify code and improve readability.
Best Use Cases: Useful for working with arrays of known elements.
33) Promises and Async/Await
TypeScript supports Promises and the async/await syntax for handling asynchronous operations.
function fetchData(): Promise<string> {
return new Promise(resolve => {
setTimeout(() => {
resolve("Data fetched!");
}, 2000);
});
}
async function fetchDataAsync() {
const data = await fetchData();
console.log(data);
}
Tips and Tricks: Promises and async/await are essential for handling asynchronous code in a synchronous-like manner.
Best Use Cases: Great for managing asynchronous operations in a readable way.
34) Generics Constraints
Generics constraints allow restricting the types that can be used with a generic type parameter.
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
Tips and Tricks: Generics constraints ensure type safety and provide more specific information to TypeScript.
Best Use Cases: Useful for working with generic types in a controlled way.
35) Type Inference for Default Values
TypeScript can infer types based on default values assigned to variables.
message = "Hello, World!"; // TypeScript infers 'message' as string
Tips and Tricks: Type inference for default values can be convenient for initializing variables without explicitly specifying types.
Best Use Cases: Useful for reducing verbosity in code and allowing TypeScript to infer types based on initial values.
THANK YOU FOR CHECKING THIS POST
You can contact me on -
Instagram - https://www.instagram.com/supremacism__shubh/
LinkedIn - https://www.linkedin.com/in/shubham-tiwari-b7544b193/
Email - shubhmtiwri00@gmail.com
You can help me with some donation at the link below Thank you👇👇
☕ --> https://www.buymeacoffee.com/waaduheck <--
Also check these posts as well
Top comments (2)
Great post!
Awesome. This helped me a lot. Thank you!