Skip to main content

23. Typescript

TypeScriptโ€‹

  • Dynamically-typed Languages
  • JS with type checking
  • Code completion
  • Needs discipline
  • Medium to large project requires ts.
  • npm init -y
  • npx tsc --init
  • npm install -g typescript
  • tsc index.ts
  • tsc index.ts --watch
  • Type safety
  • "rootDir": "./src",
  • "outDir": "./dist"
  • npm i --save-dev typescript @types/react @types/react-dom
  • all these types are available at DefinitelyType.org -> it gives us .d.ts file for js modules decleation, allowing us to use js packages as typescript packages.
// Annotation:
let sales: number = 123_456_789;
let numbers: number[] = [1, 2, 3];

// Tuples:
let user: [number, string] = [1, "Shaurya"];

// Enums:
enum Size {
Small = 1,
Medium,
Large,
}

enum ResponseStatus {
Success = 200,
NotFound = 404,
Error = 500,
}

// Enum with const => generates optimized code in js file after compilation.
const enum Size2 {
Small = 1,
Medium,
Large,
}

// enum Size {Small, Medium, Large}
// enum Size {Small=1, Medium=2, Large=3}
// enum Size {Small='s', Medium='m', Large='l'}
// const enum Size {Small='s', Medium='m', Large='l'} // compiler generates more optimized code.

// Functions:
function calculateTax(income: number): number {
return income * 0.2;
}

// Objects:
let employee: {
id: number;
name: string;
retire: (date: Date) => void;
} = {
id: 1,
name: "Shaurya",
retire: (date: Date) => {},
};
  • Using a type alias we can create a new name (alias) for a type. We often use type aliases to create custom types.
// Type alias
type Employee = {
id: number;
name: string;
retire: (date: Date) => void;
};
  • With union types, we can allow a variable to take one of many types (eg number | string).
// Union types
let weight: number | string = 1;
weight = "1kg";
  • With intersection types, we can combine multiple types into one (eg Draggable & Resizable).
// Intersection types
type Draggable = { drag: () => void };
type Droppable = { drop: () => void };

type UIWidget = Draggable & Droppable;

const MenuBox: UIWidget = {
drag: () => {
/* ... */
},
drop: () => {
/* ... */
},
};

// Literal types
type Quantity = 50 | 100;

// Nullable types
let name: string | null = null;
  • Using optional chaining (?.) we can simplify our code and remove the need for null or undefined checks.
// Optional chaining (?.)
customer?.birthdate?.getFullYear();
customers?.[0];
log?.("message");
  • Using the Nullish Coalescing Operator (??), we can fallback to a default value when dealing with null or undefined objects.
// Nullish coalescing operator
let speed: number | null | undefined = null;
let ride = {
// IMPORTANT: // speed: speed || 30; // wrong when speed is 0 => speed will be set to 30, as 0 is falsy in JS.
// speed: speed != null ? speed : 30, // have to use this
// Both are equivalent
speed: speed ?? 30,
};
  • Sometimes we know more about the type of a variable than the TypeScript compiler. In those situations, we can use the as keyword to specify a different type than the one inferred by the compiler. This is called type assertion.

  • The unknown type is the type-safe version of any. Similar to any, it can represent any value but we cannot perform any operations on an unknown type without first narrowing to a more specific type.

// The unknown type
function render(document: unknown) {
// We have to narrow down to a specific type
// before we can perform any operations
// on an unknown type.
if (typeof document === "string") {
}
}
  • The never type represents values that never occur. We often use them to annotate functions that never returns or always throw an error.
// The never type

// This function never returns because it has an infinite loop.
// so to detect unreachable code.
function processEvents(): never {
while (true) {}
// ...unreachable code here...
}

// so to detect unreachable code.
function onlyThrowsError(): never {
throw new Error("error");
// ...unreachable code here...
}

// Arrays
// - Array<number> or number[]

ts typesโ€‹

  • any
  • undefined
  • readonly
  • void

OOPSโ€‹

  • classes - blueprint for creating objects

  • interface - class can implements them.

    • interface can only be an object. Ex: It can't be equal to type tt = number | string. It is always interface tt{ key:number}
  • type lets u do union and intersection.

    -   โญโญ type cannot be re-opened to add new properties vs an interface which is always extendable.

    ```ts
    // An interface can be re-opened
    // and new values added:

    interface Mammal {
    genus: string
    }

    interface Mammal {
    breed?: string
    }

    const animal: Mammal = {
    genus: "1234",
    // Fails because breed has to be a string
    breed: 1 // has to be string
    }

    type Reptile = {
    genus: string
    }

    // You cannot add new variables in the same way
    type Reptile = {
    breed?: string
    }
    ```

    - Extending an interface

    ```ts
    interface Animal {
    name: string;
    }

    interface Bear extends Animal {
    honey: boolean;
    }

    const bear = getBear();
    bear.name;
    bear.honey;
    ```

    - Extending a type via intersections

    ```ts
    type Animal = {
    name: string;
    }

    type Bear = Animal & {
    honey: boolean;
    }

    const bear = getBear();
    bear.name;
    bear.honey;
    ```
  • abstract class

  • static property/method

  • index signatures

  • extends

  • Inheritance

  • Overriding

  • Polymorphism

  • interfaces - to define shape of objects

  • as const

  • Non-null Assertion Operator (Postfix !)

    • Writing ! after any expression is effectively a type assertion that the value isnโ€™t null or undefined.

Type operatorsโ€‹

  • keyof

    type Arrayish = { [n: number]: unknown };
    type A = keyof Arrayish;
    // A = number;

    type Mapish = { [k: string]: boolean };
    type M = keyof Mapish;
    // M = string | number;
  • typeof

    const person = { name: "shaurya", age: 11 };
    const myperson: typeof person = { age: 10 }; // error
    const myperson: typeof person = { name: "sha", age: 10 }; // no-error

Utility typesโ€‹

  • Partial<T>
    • Partial makes all properties of a type optional
  • Readonly<T>
  • Record<T, K>
    • Record letโ€™s you give a cleaner type to objects.
    • type Users = { [key: string]: User };
    • type Users = Record<string, User>;
  • Pick<T, key1 | key2 | key3>
    • Pick allows you to create a new type by selecting a set of properties (Keys) from an existing type (Type).
  • Omit<T, key1 | key2 | key3>
  • Required<T>
  • but we can create all of them ourself:- ex(s).
interface Product {
name: string;
id: number;
}

// Partial<T> = make all keys optional
type Partial<T> = {
[Key in keyof T]?: T[Key];
};

// Readonly<T> = make all keys readonly
type Readonly<T> = {
readonly [Key in keyof T]: T[Key];
};

// Record<T> = make all keys readonly
type Record<T, K> = {
[key: T]: K;
};

// Pick<T, key1 | key2 | key3> = make all keys readonly
type Pick<T, K> = {};

React TSโ€‹

  • jsx:"react-jsx"
  • React.ReactElement
  • React.ReactNode
  • React.FC
  • React.FC<propsType>, ex: React.FC<{message: string}>