Skip to content

Instantly share code, notes, and snippets.

@marsicdev
Created November 9, 2022 17:31
Show Gist options
  • Save marsicdev/0b14d0af9f6c7daff15fdaac50884a94 to your computer and use it in GitHub Desktop.
Save marsicdev/0b14d0af9f6c7daff15fdaac50884a94 to your computer and use it in GitHub Desktop.
Code snippets for TechTalk JS/TS/React mistakes
// Async/await Pitfalls
async getBooksAndAuthor(authorId) {
// const books = await bookModel.fetchAll(); // 3sec
// const author = await authorModel.fetch(authorId); // 3sec
const [books, author] = await Promise.all([
bookModel.fetchAll(), // 3sec
authorModel.fetch(authorId) // 2sec
])
return {
author,
books: books.filter(book => book.authorId === authorId),
};
}
async getAuthors(authorIds) {
// WRONG, this will cause sequential calls
// const authors = _.map(
// authorIds,
// id => await authorModel.fetch(id));
// CORRECT
const promises = _.map(authorIds, id => authorModel.fetch(id)); // [Promise<any>, Promise<any>]
const authors = await Promise.all(promises);
}
/**********************************************/
/* Example 1
/**********************************************/
function job1() {
return new Promise(function (resolve, reject) {
reject()
})
}
let promiseJob1 = job1()
promiseJob1
.then(function () {
console.log('Success 1')
})
.then(function () {
console.log('Success 2')
})
.then(function () {
console.log('Success 3')
})
.catch(function () {
console.log('Error 1')
})
.then(function () {
console.log('Success 4')
})
/**********************************************/
/* Example 2
/**********************************************/
function job2(state) {
return new Promise(function (resolve, reject) {
if (state) {
resolve('success')
} else {
reject('error')
}
})
}
let promiseJob2 = job2(true)
promiseJob2
.then(function (data) {
console.log(data)
return job2(false)
})
.catch(function (error) {
console.log(error)
return 'Error caught'
})
.then(function (data) {
console.log(data)
return job2(true)
})
.catch(function (error) {
console.log(error)
})

Strict mode

tsconfig.json

{
  ...
  "compilerOptions": {
    "strict": true,
    ...
  },
  ...
}

Enabling strict mode will enable under the hook:

  • alwaysStrict
  • strictBindCallApply
  • strictNullChecks
  • strictFunctionTypes
  • strictPropertyInitialization

Redeclaring interfaces

interface Book {
    author?: string
    numPages: number
    price: number
}

// ✅ Article is a Book without a Page
type Article = Omit<Book, 'numPages'>

// ✅ We might need a readonly verison of the Book Type
type ReadonlyBook = Readonly<Book>

// ✅ A Book that must have an author
type NonAnonymousBook = Omit<Book, 'author'> & Required<Pick<Book, 'author'>>

type animals = 'bird' | 'cat' | 'crocodile'

type mamals = Exclude<animals, 'crocodile'>
// 'bird' | 'cat'

// TypeScript ships with the following Mapped Types:
// Omit, Partial, Readonly, Exclude, Extract, NonNullable, ReturnType.

Not Relying on Type Inference

const addNumber = (a: number, b: number) => a + b

// ❌ you are hardcoding the type `number` instead of relying on what the function returns
const processResult = (result: number) => console.log(result)
processResult(addNumber(1, 1))

// ✅ result will be whatever the return type of addNumber function
// no need for us to redefine it
const processResult = (result: ReturnType<typeof addNumber>) => console.log(result)
processResult(addNumber(1, 1))

Incorrect use of Overloading

// Avoid writing several overloads that differ only in trailing parameters

// ❌ instead of this

const Params = {
    one: number, 
    two?: number, 
    three?: number
}

interface Example {
    foo(one: number): number
    foo(one: number, two: number): number
    foo(one: number, two: number, three: number): number
    foo({one, two, three}: Params): number

    foo({two: "bla"})
    foo(null, "bla")
}

// ❎ do this
interface Example {
    foo(one?: number, two?: number, three?: number): number
}

// Avoid writing overloads that differ by type in only one argument type

// ❌ instead of this
interface Example {
    foo(one: number): number
    foo(one: string): number
}

// ❎ do this
interface Example {
    foo(one: number | string): number
}

Using the Function Type

// ❌ Avoid, parameters types and length are unknown. Return type is any
const onSubmit = (callback: Function) => callback(1, 2, 3)

// ✅ Preferred, the arguments and return type of callback is now clear
const onSubmit = (callback: () => Promise<unknown>) => callback()

Relying on a Third Party for Immutability

// ✅ declare properties as readonly
interface Person {
    readonly name: string
    readonly age: number
}

// ✅ implicitely declaring a readonly arrays
const x = [1, 2, 3, 4, 5] as const

// ✅ explicitely declaring a readonly array
const y: ReadonlyArray<{ x: number; y: number }> = [{ x: 1, y: 1 }]

interface Address {
    street: string
    city: string
}

// ✅ converting all the type properties to readonly
type ReadonlyAddress = Readonly<Address>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment