Утилиты, которые повышают эффективность приложения React на Typescript

Утилиты  —  это функции, используемые для выполнения определенных задач в программном приложении. Они гибкие, легко поддерживаются и могут использоваться многократно. В этой статье будет представлен набор утилит, необходимых для повышения эффективности приложения React на TypeScript.

Эти утилиты облегчают выполнение общих задач, улучшают читаемость кода и делают его более удобным для сопровождения.

isEnum

export const isEnum = <T, R>(e: T, value: R): boolean =>
Object.values(e).includes(value);

Функция isEnum принимает два аргумента: value и enumeration. Аргумент value  —  это значение, наличие которого в перечислении нужно проверить. Аргумент enumeration  —  это объект, содержащий набор значений, которые считаются допустимыми.

Функция возвращает булево значение, указывающее, существует ли value в enumeration. Использование защиты типа с помощью value is keyof typeof enumeration гарантирует сужение типа value до значения, которое существует в перечислении.

Вот пример того, как можно использовать утилиту isEnum в коде:

enum UserRole {
ADMIN = 'ADMIN',
USER = 'USER',
}

const userRole = UserRole.ADMIN;

console.log(isEnum(UserRole, userRole)); // true

В этом примере утилита isEnum используется для проверки принадлежности userRole к типу-перечислению UserRole. Функция возвращает true, указывая на то, что userRole является членом типа-перечисления UserRole.

Утилита isEnum  —  это простой, но мощный инструмент, который поможет писать более эффективный и надежный код, снизить частоту ручных проверок и повысить читабельность.

extractQueryParams

Функция extractQueryParams  —  помощник в извлечении параметров запроса из строки поиска. Эта функция принимает два параметра: строку поиска и флаг dry. При значении true флаг dry не будет преобразовывать типы извлекаемых параметров запроса. Функция возвращает объект с извлеченными параметрами запроса.

Ниже приведен код функции extractQueryParams:

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);
};

Функция extractQueryParams может пригодиться при работе с параметрами запроса в URL. Она принимает строку поиска, которая обычно является частью URL после символа ?, и возвращает объект с извлеченными параметрами запроса. Это значительно упрощает доступ к параметрам запроса в коде, позволяя использовать ключи возвращаемого объекта для доступа к значениям.

extractQueryParams также поддерживает преобразование значений параметров запроса в различные типы данных, такие как массивы, булевы значения, числа и null. Это полезно при работе с параметрами запроса, представляющими различные типы данных.

Вот пример использования утилиты extractQueryParams:

const search = '?code=12345&name=John&active=true';
const queryParams = extractQueryParams<{ code: number, name: string, active: boolean }>(search);
console.log(queryParams);
// Вывод: { code: 12345, name: 'John', active: true }

Как видите, эта утилита позволяет извлекать параметры запроса из строки поиска и преобразовывать их в типизированный объект. В данном примере параметр code преобразуется в число, name  —  в строку, а active  —  в булево значение.

Можно также использовать параметр dry для возврата параметров запроса без преобразования типов:

const search = '?code=12345&name=John&active=true';
const queryParams = extractQueryParams<{ code: string, name: string, active: string }>(search, true);
console.log(queryParams);
// Вывод: { code: '12345', name: 'John', active: 'true' }

Эта утилита экономит много времени и усилий при парсинге параметров запроса, обеспечивая более надежный и безопасный для типов метод.

delay

Следующей утилитой в нашем наборе является функция delay. Она принимает время задержки в миллисекундах и возвращает промис, который разрешается через определенное время.

Вот реализация функции delay:

export const delay = (delayTime = 300): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, delayTime));

А вот пример того, как можно использовать функцию delay:

async function delayedAction() {
console.log("Taking action!");
await delay(500);
console.log("Action taken!");
}

Вот какие преимущества дает функция delay.

  • Помогает сохранить чистоту и читабельность кода: вместо того чтобы устанавливать вызов setTimeout и управлять обратным вызовом, можно вызвать функцию delay и передать желаемое время задержки. Это облегчает понимание того, что происходит в коде, особенно для тех, кто его читает.
  • Позволяет сделать код более гибким и пригодным для повторного использования: вместо того чтобы писать вызовы setTimeout по всему коду, можно импортировать функцию delay и применять ее везде, где нужно задержать выполнение какого-либо кода. Это упрощает управление задержками в приложении и сокращает объем кода, который необходимо написать.

В целом, функция delay  —  это простой, но мощный инструмент, помогающий писать более качественный и удобный в сопровождении код.

cb

cb  —  утилита, которая позволяет разработчикам передавать обратные вызовы ленивым способом. Она представляет собой функцию высшего порядка, которая принимает fn обратного вызова и его аргументы и возвращает новую функцию, которая может быть вызвана позже для выполнения первоначального обратного вызова, обеспечивая при этом безопасность типов и сохраняя читабельность кода.

Реализация функции cb выглядит следующим образом:

export const cb = <T extends any[], V>(fn: (...args: T) => V, ...args: T): (() => V) => {
return () => fn(...args);
};

Вот пример использования функции cb:

<button onClick={cb(toggle, !isActive)}>Toggle</button>

Вот какие преимущества дает функция cb.

  • Позволяет легко отложить выполнение функции до тех пор, пока она не понадобится, что может повысить производительность приложения.
  • Делает код более читабельным, упрощает детали выполнения обратного вызова и позволяет сфокусироваться на логике приложения.

formatCurrency

Следующая утилита в нашей коллекции  —  formatCurrency. Эта утилита используется для преобразования чисел в формат валюты, в частности долларов США. Функция принимает два параметра: value и replaceDoubleZero. value  —  это число, которое необходимо отформатировать как валюту, а replaceDoubleZero  —  булево значение, которое определяет, нужно ли удалять “.00” в конце строки валюты.

Вот реализация 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;
}

А вот пример использования formatCurrency:

const value = 123456;
const formattedValue = formatCurrency(value, true);
console.log(formattedValue); // "$123,456"

Вот какие преимущества дает formatCurrency.

  • С помощью этой утилиты можно легко форматировать числа в виде валюты, не прибегая к написанию сложного кода и не заботясь о локалях и символах валют.
  • Применение параметра replaceDoubleZero позволяет удалить “.00” из конца строки валюты, что может быть полезно в некоторых сценариях.

В целом, это простой и мощный инструмент для форматирования чисел в виде валюты.

capitalize

Утилита capitalize  —  инструмент для преобразования строк. Она принимает строку и вовзвращает новую с заглавной первой буквой. 

Реализация:

export const capitalize = (str: string): string => {
if (str.length === 0) {
return str;
}
return str[0].toUpperCase() + str.slice(1);
};

Вот пример использования утилиты capitalize в React-приложении:

const name = "john doe";
const capitalizedName = capitalize(name);
console.log(capitalizedName); // "John Doe"

Вот какие преимущества дает утилита capitalize.

  • Обеспечивает чистый и лаконичный способ форматирования строк, делая код более читабельным и удобным для сопровождения.
  • Избавляет от необходимости писать свою реализацию капитализации строк, освобождая время и ресурсы для решения других задач.

Независимо от того, работаете ли вы над небольшим проектом или крупным корпоративным приложением, утилита capitalize станет ценным инструментом в вашем арсенале.

onChange и распаковка

Следующая утилита, которую мы рассмотрим,  —  onChange. Эта функция высшего порядка принимает обработчик события и возвращает новый обработчик события, который автоматически распаковывает значение события изменения. Утилита onChange особенно полезна при работе с React-формами.

Реализация функции onChange:

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));

Рассмотрим пример использования onChange в React-компоненте:

import React, { useState } from 'react';
import { onChange } from './utils';

const ExampleForm = () => {
const [value, setValue] = useState('');
return (
<input
type="text"
value={value}
onChange={onChange(setValue)}
/>
);
};

В этом примере утилита onChange обрабатывает изменения в элементе input. Когда значение input изменяется, функция onChange вызывает функцию setValue с обновленным значением. Утилита onChange упрощает процесс распаковки значения из события изменения, что облегчает написание чистого и лаконичного кода.

Вот какие преимущества дает onChange.

  • Облегчает написание чистого и лаконичного кода.
  • Избавляет от необходимости писать повторяющийся код для распаковки значения из события изменения.
  • Упрощает управление событиями изменений в React-компоненте, поскольку утилиту onChange можно повторно использовать в нескольких компонентах.

toHumanReadable

Утилита toHumanReadable используется для преобразования строк в формате snake_case и camelCase в формат, удобный для человека. Реализация довольно проста.

  • Сначала все символы _ заменяются пробелами.
  • Затем символы нижнего регистра, за которыми следует верхний регистр, заменяются строчной буквой, за которой следует пробел и заглавная буква.
  • Потом строка преобразуется в нижний регистр, и первый символ каждого слова пишется с заглавной буквы.

Вот реализация функции toHumanReadable:

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();
});
};

Рассмотрим пример использования toHumanReadable:

import { toHumanReadable } from './utils';

const snake_case = 'snake_case';
const humanReadable = toHumanReadable(snake_case);
console.log(humanReadable); // Snake Case

parse

Утилита parse используется для парсинга строкового представления объекта JSON в строго типизированный объект. Функция принимает два аргумента: value  —  строковое представление объекта JSON; def  —  значение по умолчанию, возвращаемое в случае неудачи.

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;
}
};

Пример:

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}

Утилита parse предоставляет удобный и надежный способ парсинга строкового представления объекта JSON в строго типизированный объект. Вот какие преимущества дает parse.

  • Позволяет избежать парсинга строки JSON вручную и снижает вероятность ошибок во время выполнения, вызванных неправильным парсингом.
  • Предоставляет значение по умолчанию, возвращаемое при неудачном парсинге, поэтому является полезным инструментом для обработки граничных случаев в приложении.

Заключение

Используя эти утилиты, вы сможете сосредоточиться на написании основной функциональности. Все остальное предоставьте им.

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Radovan Stevanovic: Supercharge Your Typescript React Application with These Essential Utilities

Предыдущая статьяКак создать эффективную систему логирования с использованием Aspect и Spring Cloud Sleuth
Следующая статьяSparrow: альтернатива ChatGPT от DeepMind