prawin-s / LEARNings

0 stars 0 forks source link

Typescript Tips #6

Open prawin-s opened 3 years ago

prawin-s commented 3 years ago

TypeScript tip (1):

TypeScript infers array's type as an Array of the union of included types... which may not be precise enough.

If you want this value to be inferred as a Tuple instead, add as const

Example : Existing code -

function getDemo() {
    let title = 'A demo'
    let index = 1

    return [title, index]
}
const demo = getDemo();
const val1 = demo[0];
const val2 = demo[1];

New Code -

function getDemo1() {
    let title = 'A demo'
    let index = 1

    return [title, index] as const
}

const demo1 = getDemo1();
const val11 = demo1[0];
const val21 = demo1[1];

StackBlitz Link : https://stackblitz.com/edit/return-as-const?file=index.ts

TypeScript tip (2):

Sometimes you need to access something custom on the window object… and TypeScript complains.

Instead of throwing as any at it – and losing type safety! –describe your global thing as a part of the Window interface in a d.ts file!

One Approach (use as any)- File : index.ts

(window as any).runMyStuff()

Better Approach - File : index.d.ts

export { }

declare global {
    interface window {
        runMyStuff: () => void
    }

}

File : index.ts window.runMyStuff()


TypeScript tip (3):

When working with a directory-like object, typing it as strictly as possible helps to prevent bugs and improve maintainability.

You can use the index signature for that… but the built-in Record<Keys, Values> is way more straightforward!

type Color = 'primary' | 'secondary'

type Theme = Record<Color, string>

const themes: Theme = {
    primary: '#ccc',
    secndary: '#ddd'
}

Error - Type '{ primary: string; secndary: string; }' is not assignable to type 'Record<Color, string>'. Object literal may only specify known properties, but 'secndary' does not exist in type 'Record<Color, string>'. Did you mean to write 'secondary'?

StackBlitz Link : https://stackblitz.com/edit/ts-record?file=index.ts


TypeScript tip (4):

Keeping your objects immutable is often important for

You can make your object read-only (nested!) by adding as const assertion:

const defaultConfig = {
    initialQuery: 'Jake',
    pagination: {
        enabled: true,
        items: 10
    }
} as const

defaultConfig.pagination.items = 11

Error - Cannot assign to 'items' because it is a read-only property

StackBlitz Link : https://stackblitz.com/edit/ts-obj-as-const?file=index.ts


TypeScript tip (5):

The keyof operator extracts the keys of a given type, which makes it extremely useful for all kinds of logic that's based on properties of an object – like sorting, filtering, etc.

Combine it with a generic type to make it more universal!

Example -


interface User {
    name: string
    age: number
    points: number
}

const users: User[] = []
const books = [{ title: 'TypeScript' }]

function sortBy<T>(items: T[], prop: keyof T) {
    return // todo: implement sorting;)
}

sortBy(users, 'age')
sortBy(books, 'title')

StackBlitz Link - https://stackblitz.com/edit/ts-keyof?file=index.ts


#TypeScript tip:

"Nullish coalescing operator" sounds intimidating, but it's simply a handy way of providing a fallback in case of undefined or null value.

Typescript 3.7 introduced Nullish coalescing (??) operator which allows to get a fallback for 'null' and 'undefined'

const user1 = auth.username ? auth.username : 'Anonymous'

const user2 = auth.username ?? 'Anonymous'

Important Note : It is not a 1:1 replacement of a ternary operator Won't return fallback for '""', '0' , 'NaN' or 'false'


TypeScript tip (6):

If your function/class will work with multiple types but they need to meet some minimal criteria, you can specify the minimal shape a generic must have by extending it:

<T extends MyBaseType>

Example :

**function store<T extends { id: number }>(item: T) { console.log(saving ${item.id}) }

const book = { id: 1, title: '' } store(book)

store({ id: 32, email: '' })

store(new Date()) store(123) store('XYZ')**


TypeScript tip (7):

Using the built-in Partial<T> you can create a new type with all the properties of your base type () set to optional – useful for update logic and writing tests.

The opposite is Required<T>, which makes all the properties, well, required

type User = {
  id: number
  username: string
  nickname?: string
}

type UserUpdate = Partial<User>
let update: UserUpdate = {}

type FullUser = Required<User>
let fullUser: FullUser = {}

TypeScript tip (8):

If you want to make sure no-one mutates your array, make it readonly:

type Role = 'admin' | 'editor' | 'user'

const roles: readonly Role[] = ['editor', 'user']

roles.push('admin')
roles.concat(['admin'])

roles.splice(0, 1)
roles.slice(0, 1)

roles[1] = 'admin'
console.log(roles[1])

prawin-s commented 3 years ago

#BlitzLesson:

Array Push vs. Unshift : Array Push adds at the end while Unshift adds at the beginning.

Link : https://stackblitz.com/edit/array-add