Tiktok: I published @jgjp/fire that lets you use .catch() and .finally() everywhere

I recently found myself being grossed out by try/catch blocks, the reasons I think boil down to:

  • They are a lot of code and an extra couple blocks/indents for something that should actually be being used very often.
  • Defining a variable from inside a try block always involves a let whatever and then mutation. This adds extra complications in Typescript.
  • Even if you want to reuse an error handler in multiple places, it’s still 3 lines of code for your catch block to take the error and pass it to your handler.
  • When using promises, we can easily chain a .then, .catch, or even a .finally which is consistent with a lot of other JS syntax like .map, .reduceetc. So why can’t we do that for regular blocks of synchronous code?

It then occured to me that we can…

export const fire = async <T>(callback: () => T) =>
	new Promise<T>(async (resolve, reject) => {
		try {
			const data = await callback()
			resolve(data)
		} catch (error) {
			reject(error)
		}
	})

This allows us to do stuff like this:

const { id: userId } = await fire(async () => {
	setLoadingUser(true)
	const { data } = await makeAPIRequest('/user')
	setUser(data)
	return data
})
	.catch(setUserError)
	.finally(() => setLoadingUser(false))

const posts = await fire(async () => {
	setLoadingPosts(true)
	const { data } = await makeAPIRequest('/posts', { userId })
	setPosts(data)
	return data
})
	.catch(setPostsError)
	.finally(() => setLoadingPosts(false))

// do something with posts

I named the function fire because this syntax is fire (also we are firing a function).

I was inspired by the lodash attempt function. This is a drop in replacement for attempt that is slightly more wordy but maintains a familiar syntax and allows better handling of errors, as well as the .finally.

The performance is slightly worse than using a normal try/catch, but readability and maintainability are more important the vast majority of the time.

This package is now published at @jgjp/fire