DEV Community

Cover image for πŸš€ TypeScript Fundamentals: A Complete Guide for Beginners
Nur Alam
Nur Alam

Posted on

5

πŸš€ TypeScript Fundamentals: A Complete Guide for Beginners

πŸ“– What is TypeScript?

TypeScript is a strongly typed, object-oriented programming language that builds on JavaScript by adding static types.

⚠️ Limitations of JavaScript

  • Dynamically Typed Language: We can put a string or number or array or object on the same variable which isn’t a feasible thing. Also checking the type errors in large-scale apps is very difficult.
let a = 'Nur Alam';
a=[1,2,3]

Enter fullscreen mode Exit fullscreen mode
  • JavaScript supports object-oriented programming through prototypes and ES6 classes.
  • In JS we find the errors in runtime rather compile time.
  • When working on a large application with JS then it’s difficult to maintain a large codebase, it's hard to find bugs, and catch errors only in runtime.
  • If we need to convert the code to support old browser then it will be a issue. But typescript can be transpiled into an older version of JS easily.

** Browsers don't natively support TypeScript. We need to convert it to JS

βœ… Why Use TypeScript? (Benefits)

  • Supports older browser
  • Type safety
  • Increase Productivity
  • Fewer Bugs and less testing
  • TS has all types of JS( Number, String, Boolean, Null, Undefined, Object, Symbol) and has some own types as well (Interface, Void, Array, Tuple, Enum, Union, Intersection).

Drawbacks of TypeScript

  • Type Complexities ( Have to define types for small projects)
  • Limited Library support (Have to take additional library support sometimes)
  • Over-engineering in type design can complicate small projects.
  • Migration Challenge (Convert existing JS to TS)

πŸ› οΈ Installing and Running TypeScript

Install Typescript: npm i -g typescript

Run Typescript Code:

  • Initialize Typescript Config:
tsc --init
Enter fullscreen mode Exit fullscreen mode
  • Go to tsconfig.json and change the rootDir and outDir with uncomment to your path. Ex:
"rootDir": "./app/src/",  // TS Files
"outDir": "./app/dist/",   //Output directory
Enter fullscreen mode Exit fullscreen mode
  • Open the terminal and run β€œtsc”. It will compile ts file to js. You can set compile version in β€œtarget” of tsconfig.json. For example:
"target" : "ES5",
Enter fullscreen mode Exit fullscreen mode

***To easily run ts file, we can use ts-node-dev npm package. Here’s the process:*

//Install
npm i -g ts-node-dev
//Run
ts-node-dev --respawn --transpile-only server.ts
Enter fullscreen mode Exit fullscreen mode

πŸ”’ Primitive and Non-Primitive Types

Primitive: number, string, boolean, null, undefined, symbol
Non primitive: Array, Tuple, Object

** In JS, Objects are non-primitive. TS has array and objects both data types. We don’t get data type in TS in runtime, we get it when we compile.

πŸ†š Implicit vs Explicit Data Typing

When we define type then it’s explicit.

πŸ”  Basic Data Types with Examples

//string
let firstName: string = 'Nur'
//number
let roll: number = 123
//boolean
let isAdmin: boolean = true
//undefined
let x: undefined = undefined
//null
let y:null = null
//any. Can be any data type. Isn't recommended to use.
let z: any = 'Any'
//Array
let friends: string[] = ['Alice', 'Rachel']
//tuple ->Special type of array which maintains type order
let coordinates: [number, number] = [5,5]
//Object
const user: {
   firstName: string;
   middleName?: string; //Optional
   lastName: string;
} = {
   firstName: 'Nur',
   lastName: 'Alam'
}
Enter fullscreen mode Exit fullscreen mode

πŸ“¦ Object Literals

It defines its own type. In below example company name is fixed so we can define a new type for that.

const user: {
   company: 'Google', // Literal Type
   firstName: string;
   middleName?: string; //Optional
   lastName: string;
} = {
   company: 'Google',
   firstName: 'Nur',
   lastName: 'Alam'
}
Enter fullscreen mode Exit fullscreen mode

πŸ—οΈ Functions in TypeScript

//Normal Function with types and predefined value
function add(num1: number, num2: number = 10): number {
 return num1 + num2;
}


//Arrow Function
const add = (num1: number, num2: number): number => num1 + num2;


//Method -> A function inside JS Object
const user = {
 name: "Nur",
 balance: 0,
 addBalance(balance: number): number {
   return this.balance + balance;
 },
};


//Callback Function - A callback function is a function passed as an argument to another function and is executed later within that function.
//Here a arrow function is passed in map function
const num: number[] = [1, 2, 3];
const doubleNum: number[] = num.map((elem: number): number => elem * 2);
Enter fullscreen mode Exit fullscreen mode

πŸ”„ Spread & Rest Operators

​​Spread operator expands elements, while the rest operator collects arguments into an array.

//Spread Operator
const arr1: number[] = [1, 2, 3];
const arr2: number[] = [4, 5, 6];


const combineArr: number[] = [...arr1, ...arr2];


//Rest Operator -> Used to collect multiple arguments into a single array.
const employee = (...employee: string[]) => {
 employee.forEach((em: string) => console.log(`Onboard ${em}`));
};


employee("Nur", "Abul", "Rimon");
Enter fullscreen mode Exit fullscreen mode

πŸ—οΈ Destructuring in TS:

//Object Destructuring
const user = {
 id: 123,
 name: {
   firstName: 'Nur',
   lastName: 'Alam',
 }
}
//Destructuring id as userID ( Name Alias) and firstName
const {id: userID, name: { firstName }} = user;


//Array Destructure
const friends = ["Joy", "Akash", "Karim", "Latif", "Opu" ]
//Destructuring Karim as bestfriend and latif, opu in rest
const [,,bestFriend, ...rest] = friends
Enter fullscreen mode Exit fullscreen mode

πŸ”„ Type Alias

//Type Alias in object
type User = {
 firstName: string;
 middleName?: string; //Optional
 lastName: string;
}
const user1: User = {
 firstName: 'Nur',
 lastName: 'Alam'
}


//Type Alias in Function
type Add = (num1: number, num2: number) => number
const add: Add = (num1, num2) => num1+num2;
Enter fullscreen mode Exit fullscreen mode

πŸ”— Union, Intersection, Nullish Coalescing Operator

// Ternary Operator
const hasPassed = mark >=40 ? "Passed" : "Failed";


//Union
const user = User1 | User2 // Can be either of User type
//Intersection
const user = User1 & User2 // Combination of both the type and will contain all field


// Nullish Coalesing Operator
// Used when need to make decision based on null or undefined
const isAdmin = null;
const userType = isAdmin ?? "Normal User";


//Optional Chaining
const isPassed = student?.marks ?? "Didn't attend exam"
Enter fullscreen mode Exit fullscreen mode

🚫 Never, Unknown, Nullable Types

never is used for functions that never return or reach the end.

function throwError(message: string): never {
  throw new Error(message);
}
Enter fullscreen mode Exit fullscreen mode

unknown represents a value with an unknown type and requires type checking before use.

let data: unknown = "Hello";
if (typeof data === "string") {
  console.log(data.toUpperCase());
}
Enter fullscreen mode Exit fullscreen mode

Nullable types (null and undefined) allow variables to have no value or be unassigned.

let name: string | null = null;
let age: number | undefined;
Enter fullscreen mode Exit fullscreen mode

🧐 Type Assertion & Type Narrowing

Type Assertion tells TypeScript to treat a value as a specific type.

let value: unknown = "Hello, TypeScript!";
let strLength: number = (value as string).length;
console.log(strLength); // Output: 18
Enter fullscreen mode Exit fullscreen mode

Type Alias vs Interface:

The interface is primarily used to define the structure of objects and is extendable using the extends keyword, making it ideal for object-oriented designs. It also supports declaration merging, allowing multiple declarations of the same interface to automatically combine.

On the other hand, type is more flexible and can define primitives, unions, tuples, and object types but does not support declaration merging. It uses the intersection operator (&) to combine types. For example, using an interface:

interface Person {
  name: string;
  age: number;
}
interface Employee extends Person {
  salary: number;
}
Enter fullscreen mode Exit fullscreen mode

Whereas with a type alias:

type PersonType = { name: string; age: number; };
type EmployeeType = PersonType & { salary: number; };

Merging
interface User {
  name: string;
}

interface User {
  age: number;
}

// Result: { name: string; age: number; }
Enter fullscreen mode Exit fullscreen mode

πŸ› οΈ Generics

Generics in TypeScript allow us to create reusable components that can work with a variety of data types while maintaining type safety. Instead of specifying a fixed type, generics use type parameters that are specified when the function, class, or interface is used.

//Generic Array
type GenericArray<T> = Array<T>;
//Same as GenericArray[number]
const roll: GenericArray<number> = [1, 2, 3];

//Generic Object
const user: GenericArray<{ name: string, age: number}> = [
 {
   name: "Nur",
   age: 25
 }
]
//Generic Tuple
type GenericTuple<X,Y> = [X,Y]
const user: GenericTuple<string, string> = ["Mr. X", "Admin"]
//Generic with interface
interface ApiResponse<T> {
  status: number;
  data: T;
}

const userResponse: ApiResponse<{ name: string; age: number }> = {
  status: 200,
  data: { name: "Alice", age: 25 },
};

const productResponse: ApiResponse<string[]> = {
  status: 200,
  data: ["Laptop", "Phone"],
};

//Generic in Function
const createGenericArr = <T>(param: T): T[] =>{
 return [param];
}

const result = createGenericArr<string>("Hello");

//Generic in tuple
const genericTuple =<T,Q>(param1: T, param2: Q): [T,Q]=>{
 return [param1, param2];
}
Enter fullscreen mode Exit fullscreen mode

🚧 Constraints:

Constraints in TypeScript limit the types that can be used in generics to ensure type safety.

function printLength<T extends { length: number }>(item: T) {
  console.log(item.length);
}

printLength("Hello");      // βœ… Works (string has length)
printLength([1, 2, 3]);    // βœ… Works (array has length)
// printLength(123);       // ❌ Error (number has no length)
Enter fullscreen mode Exit fullscreen mode

πŸ”‘ keyof Constraint

Limits a generic type to the keys of another type.

interface Person {
  name: string;
  age: number;
}

function getValue<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

const person: Person = { name: "Alice", age: 25 };
console.log(getValue(person, "name")); // βœ… Output: Alice
// getValue(person, "height");         // ❌ Error: "height" is not a key of Person
Enter fullscreen mode Exit fullscreen mode

⚑ Conditional Types:

Conditional types allow you to create types that depend on a condition.

type IsString<T> = T extends string ? "Yes" : "No";

type Test1 = IsString<string>;  // "Yes"
type Test2 = IsString<number>;  // "No"
Enter fullscreen mode Exit fullscreen mode

Mapped Types:

Mapped types allow you to transform existing types by looping over their properties.

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

// Make all properties optional
type PartialPerson = {
  [K in keyof Person]?: Person[K];
};

const person: PartialPerson = { name: "Alice" }; // `age` is optional
Enter fullscreen mode Exit fullscreen mode

πŸ› οΈ Utility Types

  • Pick β†’ Select specific properties from a type
interface Person {
  name: string;
  age: number;
  address: string;
}

type NameAndAge = Pick<Person, "name" | "age">;

const person: NameAndAge = { name: "Alice", age: 25 };
Enter fullscreen mode Exit fullscreen mode
  • Omit β†’ Exclude specific properties from a type
type WithoutAddress = Omit<Person, "address">;

const personWithoutAddress: WithoutAddress = { name: "Bob", age: 30 };

Enter fullscreen mode Exit fullscreen mode
  • Required β†’ Make all properties mandatory
interface Product {
  id: number;
  description?: string;
}

type RequiredProduct = Required<Product>;

const product: RequiredProduct = { id: 1, description: "New product" };
Enter fullscreen mode Exit fullscreen mode
  • Readonly β†’ Make all properties immutable
interface Car {
  model: string;
  year: number;
}

const car: Readonly<Car> = { model: "Tesla", year: 2023 };
// car.model = "BMW"; // ❌ Error: Cannot assign to 'model' because it is a read-only property
Enter fullscreen mode Exit fullscreen mode
  • Record β†’ Create an object type with specified keys and value types
type UserRole = "admin" | "user" | "guest";

const roles: Record<UserRole, string> = {
  admin: "Full Access",
  user: "Limited Access",
  guest: "Read-Only Access",
};
Enter fullscreen mode Exit fullscreen mode
  • Partial β†’ Make all properties optional
interface Profile {
  username: string;
  email: string;
}

type OptionalProfile = Partial<Profile>;

const userProfile: OptionalProfile = { username: "Nur" }; // `email` is optional
Enter fullscreen mode Exit fullscreen mode

Enum:

Enums allow us to define a set of named constants. It makes code more readable and manageable when dealing with constant values and
enforces valid inputs over plain strings or numbers.

enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

let move: Direction = Direction.Left;
console.log(move); // Output: "LEFT"
Enter fullscreen mode Exit fullscreen mode

Template Literal Types:

Template Literal Types build complex types using string literals and union types.

type HttpMethod = "GET" | "POST";
type ApiRoute = "/users" | "/products";

type Endpoint = `${HttpMethod} ${ApiRoute}`;

const getUser: Endpoint = "GET /users";  // βœ…
const invalid: Endpoint = "DELETE /users"; // ❌ Error
Enter fullscreen mode Exit fullscreen mode

Conclusion

TypeScript offers powerful tools for building scalable and robust applications. It enhances JavaScript with static typing, better tooling, and modern features.

Start using TypeScript today to write cleaner, safer, and more efficient code!

Got questions or feedback? Drop a comment below! πŸ‘‡

Follow me to learn OOP in Typescript.

Happy Coding! πŸš€

Image of Docusign

πŸ› οΈ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more