С каждым годом TypeScript становится все популярнее и думаю уже почти каждый фронтенд разработчик использовал его в своих проектах.
В данной статье я бы хотел дать некоторые советы по использованию возможностей TypeScript, которые помогут вам сократить количество ошибок в процессе разработки.
Используйте более строгие utility-types
TypeScript предоставляет достаточно много типов преобразования, которые существенно упрощают работу, но для некоторых из них я бы рекомендовал использовать более строгие версии.
Давайте рассмотрим реализацию типа Omit.
type Omit<T, K extends string | number | symbol> = { [P in Exclude<keyof T, K>]: T[P]; }
Главная проблема заключается в том, что в качестве параметра K
сюда можно передать несуществующий ключ.
interface Todo {
title: string;
description: string;
completed: boolean;
createdAt: number;
}
type TodoPreview = Omit<Todo, "qwerty">;
Для решения данной проблемы я бы предложил вам использовать тип StrictOmit из библиотеки ts-essentials или добавить свою реализацию.
type StrictOmit<T, K extends keyof T> = { [P in Exclude<keyof T, K>]: T[P]; }
Указывайте тип для Object.keys
При работе с Object.keys вы всегда будете получать тип string[]
, хотя хотелось бы вместо string
получать список ключей.
Для решения данной проблемы вы можете явно указать тип для переменной со списком ключей объекта.
interface Todo {
title: string;
description: string;
completed: boolean;
}
let todo: Todo = {
title: 'Title',
completed: true,
description: 'Description'
};
let todoKeys = Object.keys(todo) as (keyof Todo)[];
Используйте Branding
Branding позволяет сделать проверку типов более строгой. Давайте рассмотрим это на следующем примере.
Есть функция, которая выводит дату в определенном формате.
function dateFormatter(date: string) : void {}
Так же есть объект todo
у которого нужно вывести дату с помощью функции dateFormatter
interface Todo {
title: string;
description: string;
completed: boolean;
createdDate: string;
}
let todo: Todo = {
title: 'Title',
completed: true,
description: 'Description',
createdDate: '2022-02-26T13:43:59.175Z'
};
Главная проблема заключается в том, что в dateFormatter
можно передать строку с любым значением, а не только с датой.
Для решения данной проблемы можно добавить новый тип DateISOString
и использовать его для работы с датами.
type DateISOString = string & {
_type: 'date'
}
interface Todo {
title: string;
description: string;
completed: boolean;
createdDate: DateISOString;
}
let todo: Todo = {
title: 'Title',
completed: true,
description: 'Description',
createdDate: '2022-02-26T13:43:59.175Z' as DateISOString
};
function dateFormatter(date: DateISOString) : void {}
Теперь при попытке передать в dateFormatter
тип string
будет ошибка.
Комментарии (7)
NN1
27.02.2022 09:58https://github.com/ts-essentials/ts-essentials#strictomit
Вот разница.
Вопрос в том хотите ли вы получить ошибку сборки или просто пустой тип в случае несуществующих свойств.aamonster
27.02.2022 10:06Почему пустой-то? Исключили то, чего там и так не было – т.е. получим исходный тип, нет?
Вообще вижу два совершенно разных сценария использования, в одном StrictOmit добавит чуть спокойствия (подстрахует от опечаток и т.п.), а в другом (когда он использован не по делу) с ним просто не скомпилируется.
impwx
27.02.2022 12:06+4Пример с датой — это грязный хак. На одной стороне нужно все время использовать явное приведение типов, на другой — получаем непонятную ошибку. А самое печальное — на практически любых операциях (строковые функции для строк, математические операторы для чисел) branding слетает и остается только базовый тип. В результате у нас остается гора бойлерплейт-кода, которая не дает существенной защиты от ошибок.
При этом для работы с датами в JS есть встроенный тип Date (довольно ущербный, но все же), есть MomentJS / Luxon, и есть всякие JSON-декодеры типа io-ts для превращения прилетающих строк в объекты нормальных типов.
iproman
28.02.2022 19:02Не отрицаю что возможно это удобно, но по мне, большая обертка с типизацией, усложняет код.
vsviridov
Не совсем понимаю смысл с StrictOmit, на выходе то-же самое, но компиляционные расходы выше...