sahilrajput03 / learn-typescript

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Learn Typescript

Getting keys of plain object

let car = {
    a: 10,
    b: 20
}

let man: typeof car = {
    // field names are typed here i.e, "a", "b"
}

Getting keys of enum?

enum Enum {
  A,
}
 
let a = Enum.A; // 0
let nameOfA = Enum[a]; // "A"

Typing the value of then (cloned from learn-axios.md)

  • Typing the .then value:
axios.get().then((res: AxiosResponse<string>) => {
	res.data // string
}

Geenrics with arrow functions

Source: 1https://stackoverflow.com/a/45576880, 2

const foo = <T,>(x: T) => x;

Utility Types

Docs: Click here

Awaited<Type>, Partial<Type>, Required<Type>, Readonly<Type>, Record<Keys, Type>, Pick<Type, Keys>, Omit<Type, Keys>, Exclude<UnionType,
ExcludedMembers>, Extract<Type, Union>, NonNullable<Type>, Parameters<Type>, ConstructorParameters<Type>, ReturnType<Type>, InstanceType<Type>,
ThisParameterType<Type>, OmitThisParameter<Type>, ThisType<Type>, Intrinsic String Manipulation Types, Uppercase<StringType>, Lowercase<StringType>,
Capitalize<StringType>, Uncapitalize<StringType>.	

We can type req.body in express like that

Source: Click here

image

Get type from values of an array β™₯πŸ’•β€πŸ˜˜

Source: Click here

const animals = ['cat', 'dog', 'mouse'] as const
type Animal = typeof animals[number]
// type Animal = 'cat' | 'dog' | 'mouse'

Amazing/Awesome that we can remove a type from a union type as well

Source: Click here

We can get list of keys as type via this

interface car {
	bmw: string
}

type m1 = keyof typeof car;
// or in older version we could do like that too:
// type m1 = keyof car;

let myhome: m1 = 'bmw'
let yourHome: m1 = 'thisThrowsError'

Open the real logic file when you ctrl+click on function of any library in typescript project

By default the .d.ts file is opened for the library function, but you can open the logic via clicking the respective logic file for currently openeed .d.ts file"

image

Extract nested type from a type

Source: Click here

type car = {
bmw: string;
}

// We get, m: string
type m = car['bmw'];

Using default vaues in generics

export type Maybe<T=number> = T[] | string[];

let numberValues: Maybe = [1,2,3]
let stringValues: Maybe<string> = ['sahil', 'mohit']

Using generics with mongodb's documents:

Proposal to Eric question!

typescript playground: Click here

type MessagesType<T = String[]> = Array<
  {
    content: string;
    matchlist: T;
  }>;

// Simple
let messagesData: MessagesType = [
  {
    content: 'hi there',
    matchlist: ['5349b4ddd2781d08c09890f3', '5349b4ddd2781d08c09890f4']
  }
]

// With subdocuments type
type matchListsType = Array<{ participants: string[]; updated: number; }>

let messagesWithMatchlistsData: MessagesType<matchListsType> = [
  {
    content: 'hi there',
    matchlist: [{ updated: 1674391530204, participants: ['1119b4ddd2781d08c09890g9', '7779b4ddd2781d08c09890k9'] }]
  }
]
  • Using multiple typescript config files

Source: Click here

image

  • Merging two types:
// using `type`
type user = {
    name: string;
}

type roles = {
    isAdmin: boolean;
}

let k: user & roles = {
    name: 'sahil',
    isAdmin: true
}
	
// Using `interface`
interface user {
    name: string;
}

interface roles {
    isAdmin: boolean;
}

let k: user & roles = {
    name: 'sahil',
    isAdmin: true
}
  • Optionla chaining:
const k = a?.b?.c // k will be undefined if anything is undefined in this chain
const m = a?.['some-property'] // another syntax helpful to get properties with hyphens becoz hyphen property doesn't work with `?.some-property`
const n = a?.() // call function if it's not undefined
  • Generating types from existing function of libraries:
// Example: 1
let contractBase = new web3Base.eth.Contract([])
export type contractType = typeof contractBase
type getContractsReturnType = {
	[key: string]: contractType
}
const getContracts = async (web3: web3Type): Promise<getContractsReturnType> => {	return new Promise(res => {...})	}
////////

// Example: 2
let web3Base = new Web3(null) // This is to extract type ~Sahil
export type web3Type = typeof web3Base
const getWeb3 = (): Promise<web3Type> => {	new Promise(res => {...}	)
}
  • Using .d.ts files in typescript

image

  • Getting type via magic from a zod validator:

Source: See source of next point in this content.

Why this is game change? Because say in nextjs (typescript project) I can simply import get the type from the zod validator we created say for an api and then we can simply ipmort that type in frontend ui code to make use of types simply bcoz of the validator's inference's magic, yikes. This make building consuming type-safe apis in frontend like a piece of cake, amazing!

image

  • Making use of validator i.e., zod for writing type safe code

Source: Click here

image

  • Generics in typescrpt:
type Container<T> = { value: T };

let ss: Container<string>
// ss = "coal" // throws error: Type 'string' is not assignable to type 'Container<string>' 
// ss.value = 23 // throws error: Type 'number' is not assignable to type string.
ss = {value: "my text"}  // works

console.log(ss)
  • Thats how enums work in typescript:

source: https://www.w3schools.com/typescript/typescript_enums.php

enum Tabs {
	Notifications = 'notifications',
	ChangePassword = 'change_password',
	Help = 'help',
}

console.log(Tabs.Notifications) // notifications
console.log(Tabs.ChangePassword) // change_password
console.log(Tabs.Help) // help

// for react you can use:
const [tab, setTab] = useState<Tab>(Tab.Notifications)
  • A popular and trusted validation library for ts: https://github.com/colinhacks/zod (9k*)
  • Move tiny things of typescript from learn-react, learn-nextjs, learn-express repos to here.
  • Exporting Types is same exporting anything else: src
// a.ts
export interface UserList {
	id: number;
	name: string;
	email: string;
	phone: string;
}

// b.ts
import {UserList} from './a';

let users: UserList[]

users.map(u => {
	u.<SHOULD AUTOCOMPLETE WITH TYPES>
})

image

  • Reexports: src

image

  • Learn more about exports: image

  • Solution to assigning variable to window object without any error in TYPESCRIPT:

image

I used it like:

declare global {
	interface Window {
		userLoggedIn: any;
	}
}
window.userLoggedIn = {name: 'Sahil'};
  • Learn typescript types in in javascript with jsdocs: Click here

  • Enable typescript check in js projects:

    You can do either a workspace level or user settings level or both.

    Source: ttps://code.visualstudio.com/docs/nodejs/working-with-javascript#_type-checking-javascript

    Tldr: Search for ts-check in VSCode settings, and enable js/ts.implicitProjectConfig.checkJs setting @ workspace level. Using this settings user level is also encouraged as it will show all the warnings for you at all times but since you want all users of the project to have this feature enabled by defautl you must enable this workspace level too(even if you have it enabled @ user level).

Enumbs vs. objects?

Enums are good but I am considering advantage of 1. sharing the options(label,value) pairs directly from the backend, 2. we can control label values from the backend, 3. Removing a key-value pair is very easy as it won't result in dangling pointer values(coz enums are by default 0,1,2,etc indices only). Actually I think objects are better fit, for e.g.,

Check below code in ts playgorund: Click here

// Dropdown Options
// Benefits:
// 1. We can CHANGE labels directly of frontend without breaking anything
// 2. ADD/REMOVE new key-value pairs directly from backend and frontend can consume it accordingly 
// WARNING: Never change the key names of below object as it can result in mismatched/dangling values
const bodyType = {
  THIN: "Thin",
  AVERAGE: "Average",
  FIT_MUSCULAR: "Fit / Muscular",
  LITTLE_EXTRA: "A little extra",
  LARGE_PLUS_SIZE: "Large / Plus Size",
}

const dropDownOptions = Object.entries(bodyType).map(([value, label]) => ({label, value}))

console.log('options?', dropDownOptions)

type bodyTypeValue = keyof typeof bodyType;
let person1: bodyTypeValue = 'LARGE_PLUS_SIZE' // gives autocomplete as well
// Below throws error
let person2: bodyTypeValue = 'something else?'

// From api we can send options and frontend can parse it accordingly
// res.send(JSON.stringify(dropDownOptions))

Enums? Bad/Good?

Please see Enumbs vs. objects? section above for more advanced levaraging power of enum like structure from the just plain objects.**

Enum Patterns, advantages and disadvantages:

# Why Enums?

Why?
- More reliable when we change synonyms alternate for labels (Robust)
- No more case sensitive problems for labels
- More readable code in frontend and backend for labels
- More flexible with multilingual words for labels
Trade Offs (for index based enums)?:
- Less readable in database values in database
- If enum backing number value is changed in code, all values in database need to be updated

UPDATE: 7 Dec, 2022: Actually above discussed trade off of number based enum can be solved simply by using string based enums and we can specify more meaning enum values for each enum option. Yikes For using string enums refer below links.

  • TypeScript string enums, and when and how to use them: Click here
  • How To Convert A TypeScript Enum To A JavaScript Array Or String: Click here

Typescriptlang Playground of below code: Click here

image

πŸ₯° ❣ πŸ’“ β₯ πŸ’‘ Thats how you fix a type error when you need need to access values defined on the req (request) object in express routes

Source: Click here

image

About