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 fornull 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 withnull 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 calledtype 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 canimplements
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}
- interface can only be an object. Ex: It can't be equal to
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
.
- Writing ! after any expression is effectively a type assertion that the value isnโt
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}>