Supercharge Your Typescript React Application with These Essential Utilities
Utils are functions used to perform specific tasks in a software application. They are designed to be reusable, flexible, and easy to maintain. This blog post will discuss a set of utils that can be used to supercharge your Typescript React application.
These utils are designed to make common tasks easier, improve code readability, and make your code more maintainable.
isEnum
export const isEnum = <T, R>(e: T, value: R): boolean =>
Object.values(e).includes(value);
The isEnum
function takes two arguments: value
and enumeration
. The value
argument is the value that needs to be checked if it exists within the enumeration. The enumeration
argument is an object that contains a set of values that are considered valid values.
The function returns a boolean value indicating whether the value
exists within the enumeration
or not. The use of a type guard with value is keyof typeof enumeration
ensures that the type of value
is narrowed to a value that exists within the enumeration.
Here’s an example of how you might use the isEnum
util in your code:
enum UserRole {
ADMIN = 'ADMIN',
USER = 'USER',
}
const userRole = UserRole.ADMIN;
console.log(isEnum(UserRole, userRole)); // true
In this example, the isEnum
util is used to check if the userRole
belongs to the UserRole
enum. The function returns true
, indicating that the userRole
is indeed a member of the UserRole
enum.
The isEnum
util is a simple, yet powerful tool that can help you write more efficient and robust code by reducing the need for manual checks and making your code more readable.
extractQueryParams
The next util is the extractQueryParams
function is a helper for extracting query parameters from a search string. This function takes in two parameters: the search string and a boolean flag "dry". When set to true, the "dry" flag will not convert the types of the extracted query parameters. The function returns an object with the extracted query parameters.
Here is the code for the extractQueryParams
function:
export const extractQueryParams = <T>(search: string, dry = false): T => {
if (!search) return {} as T;
return search
.replace("?", "")
.split("&")
.reduce((data: T, item) => {
const [k, v] = item.split("=");
if (!k || !v) return data;
if (dry) return { ...data, [k]: v };
if (v.includes(",")) return { ...data, [k]: v.split(",") };
if (["true", "false"].includes(v)) return { ...data, [k]: v === "true" };
if (v === "null") return { ...data, [k]: null };
if (!Number.isNaN(+v)) return { ...data, [k]: +v };
return { ...data, [k]: v };
}, {} as T);
};
This function can be very useful when working with query parameters in a URL. It takes the search string, which is typically the part of the URL after the “?” symbol and returns an object with the extracted query parameters. This makes it much easier to access the query parameters in your code, as you can simply use the keys of the returned object to access the values. Additionally, the function also supports converting the values of the query parameters to different data types, such as arrays, booleans, numbers, and null. This can be useful when working with query parameters representing different data types.
Here’s an example of using the extractQueryParams
utility:
const search = '?code=12345&name=John&active=true';
const queryParams = extractQueryParams<{ code: number, name: string, active: boolean }>(search);
console.log(queryParams);
// Output: { code: 12345, name: 'John', active: true }
As you can see, this utility allows you to extract query parameters from a search string and convert them into a typed object. In this example, the code
parameter is converted to a number, name
is converted to a string, and active
is converted to a boolean.
You can also use the dry
parameter to return the query parameters without type conversion:
const search = '?code=12345&name=John&active=true';
const queryParams = extractQueryParams<{ code: string, name: string, active: string }>(search, true);
console.log(queryParams);
// Output: { code: '12345', name: 'John', active: 'true' }
This utility can save you a lot of time and effort in parsing query parameters and provides a more robust and type-safe way.
delay
The next util in our set is the delay
function. This function takes in a delay time in milliseconds and returns a Promise that resolves after the specified amount of time.
Here is the implementation of the delay
function:
export const delay = (delayTime = 300): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, delayTime));
Here is an example of how you can use the delay
function:
async function delayedAction() {
console.log("Taking action!");
await delay(500);
console.log("Action taken!");
}
The benefits of using the delay
function are numerous. Firstly, it helps to keep your code clean and readable. Instead of setting a setTimeout call and managing the callback, you can call the delay function and pass in the desired delay time. This makes it easier to understand what is happening in your code, especially for others looking at it. Secondly, it helps to make your code more flexible and reusable. Instead of writing setTimeout calls throughout your code, you can import the delay function and use it wherever you need to delay the execution of some code. This makes it easier to manage delays throughout your application and reduces the amount of code that needs to be written. Overall, the delay
function is a simple yet powerful tool that can help you write better and more maintainable code.
cb
The cb
utility is a simple utility that allows developers to pass callbacks in a lazy manner. It is a higher-order function that takes in a callback fn
and its arguments, and returns a new function that can be invoked later to execute the original callback while providing type safety and maintaining the readability of the code
The implementation of the cb
function is as follows:
export const cb = <T extends any[], V>(fn: (...args: T) => V, ...args: T): (() => V) => {
return () => fn(...args);
};
Here’s an example of how you can use the cb
function:
<button onClick={cb(toggle, !isActive)}>Toggle</button>
The benefits of using the cb
function are numerous. It makes it easy to delay the execution of a function until it is needed, which can improve the performance of your application. Finally, it can also make your code more readable by abstracting away the details of executing a callback and instead focusing on the logic of your application.
formatCurrency
The next utility in our set is formatCurrency
. This utility is used to format numbers as currency, specifically US dollars. The function takes in two parameters: value
and replaceDoubleZero
. The value
parameter is the number that needs to be formatted as currency, and the replaceDoubleZero
parameter is a boolean that determines whether or not the ".00" at the end of the currency string should be removed.
Here’s the implementation of formatCurrency
:
export function formatCurrency(value: number, replaceDoubleZero?: boolean) {
const formattedValue = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
}).format(value);
if (replaceDoubleZero) {
return formattedValue.replace(".00", "");
}
return formattedValue;
}
And here’s an example of how to use formatCurrency
:
const value = 123456;
const formattedValue = formatCurrency(value, true);
console.log(formattedValue); // "$123,456"
The benefits of using formatCurrency
are clear. Using this utility, you can easily format numbers as currency without having to write complex code or worry about locales and currency symbols. Additionally, by using the replaceDoubleZero
parameter, you can remove the ".00" from the end of the currency string, which can be useful in certain scenarios. Overall, formatCurrency
is a simple yet powerful tool for formatting numbers as currency in your TypeScript React applications.
capitalize
The capitalize
utility function is a simple but effective tool for transforming strings. Its purpose is to take string input and return a new string with the capitalized first letter. Here is the implementation:
export const capitalize = (str: string): string => {
if (str.length === 0) {
return str;
}
return str[0].toUpperCase() + str.slice(1);
};
Here’s an example of how you might use the capitalize
utility in your React application:
const name = "john doe";
const capitalizedName = capitalize(name);
console.log(capitalizedName); // "John Doe"
The benefits of using the capitalize
utility is twofold. Firstly, it provides a clean and concise way to format strings, making your code more readable and maintainable. Secondly, it eliminates the need for you to write your implementation of string capitalization, freeing up time and resources to focus on other tasks. Whether you're working on a small project or a large enterprise application, the capitalize
utility is valuable in your toolkit.
onChange and unpack
The next utility function we will discuss is onChange
. This higher-order function takes an event handler and returns a new event handler that automatically unpacks the value of a change event. The onChange
utility is particularly useful when working with React forms.
Here’s an implementation of the onChange
function:
import { ChangeEvent } from 'react';
type E = ChangeEvent<
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
>;
export const unpackE = (e: E): string => {
return e.target.value;
};
export const onChange = (handler: (v: string) => void) => (e: E) =>
handler(unpackE(e));
Let’s see an example of how onChange
can be used in a React component:
import React, { useState } from 'react';
import { onChange } from './utils';
const ExampleForm = () => {
const [value, setValue] = useState('');
return (
<input
type="text"
value={value}
onChange={onChange(setValue)}
/>
);
};
In this example, the onChange
utility handles changes to the input element. When the input value changes, the onChange
function calls the setValue
function with the updated value. The onChange
utility abstracts away the process of unpacking the value from the change event, making it easier to write clean and concise code.
Using onChange
has several benefits. First, it makes it easier to write clean and concise code. Second, it eliminates the need to write repetitive code to unpack the value from change events. And finally, it makes it easier to manage change events in a React component, as the onChange
utility can be reused across multiple components.
toHumanReadable
The toHumanReadable
util is used to convert a snake_case or camelCase string into a human-readable format. The implementation is quite straightforward: it first replaces all instances of _
with spaces, then replaces instances of lowercase followed by uppercase with the lowercase letter followed by a space and the uppercase letter. The string is then converted to lowercase, and the first character of each word is capitalized.
Here’s an implementation of the toHumanReadable
function:
export const toHumanReadable = (str: string) => {
return str
.replace(/_/g, " ")
.replace(/([a-z])([A-Z])/g, "$1 $2")
.toLowerCase()
.replace(/(^|\s)\S/g, function (t) {
return t.toUpperCase();
});
};
Let’s see an example of how toHumanReadable
can be used:
import { toHumanReadable } from './utils';
const snake_case = 'snake_case';
const humanReadable = toHumanReadable(snake_case);
console.log(humanReadable); // Snake Case
parse
The parse
utility function is used to parse a string representation of a JSON object into a strongly-typed object. The function takes two arguments: value
, the string representation of the JSON object, and def
, a default value to return if the parsing fails.
export const parse = <T>(value: string | undefined, def: T): T => {
if (!value) return def;
try {
return JSON.parse(value) as T;
} catch (e) {
return def;
}
};
Example:
const jsonString = '{"name": "John Doe", "age": 30}';
const parsedValue = parse<{name: string, age: number}>(jsonString, {name: '', age: 0});
console.log(parsedValue); // {name: 'John Doe', age: 30}
The parse
utility function provides a convenient and reliable way to parse a string representation of a JSON object into a strongly-typed object. This helps avoid manual JSON string parsing and reduces the chance of runtime errors caused by incorrect parsing. The function also provides a default value to return if the parsing fails, making it a useful tool for handling edge cases in your application.
Final Words
In conclusion, these custom utilities offer a variety of functions that can greatly simplify the process of writing and maintaining code. From checking whether a value is an enumeration to parsing strings into JSON, these functions are designed to make the developer’s life easier. Using these utilities, developers can focus on writing their core functionality and let the utilities handle the rest. The benefits of using these utilities include less code to write, fewer bugs, and improved code readability. Overall, these utilities are a valuable addition to any developer’s toolkit.
Level Up Coding
Thanks for being a part of our community! Before you go:
- 👏 Clap for the story and follow the author 👉
- 📰 View more content in the Level Up Coding publication
- 🔔 Follow us: Twitter | LinkedIn | Newsletter
🚀👉 Join the Level Up talent collective and find an amazing job