5 个 TypeScript 库来改进你的代码
5 个 TypeScript 库来改进你的代码
我正在参加「掘金·启航计划」!
在过去的几年里,TypeScript
语言除了增长用户之外几乎什么都没做。它已被许多 Web 开发人员评为最喜欢的语言。使用纯JavaScript
代码的前端工作变得越来越少。
但是,有时 TypeScript
并没有充分发挥其潜力。导致过多或使用过多any
是最常见的错误之一。
在本文中,我们将看到5 个 TypeScript 库,这些库将增强您的 TypeScript
体验并增加您对其静态类型的信心。这些最小的库将提高开发人员的开发效率。
1、zod
TypeScript
的薄弱环节是仅在编译时验证。一旦它被解析和构建,所有类型都被删除。在以下情况下,这可能会导致出现一些错误:
- 编译器以一些假设信任开发人员(开发人员使用
any
,ts-expect-error
,cast
等忽略类型检查...) - 网络返回的 REST 模式与预期不同。
让我们看一个例子:
interface User {
name: string;
email: string;
}
async function fetchUser(id: string): User {
const url = `/users/${id}`;
const response = await fetch(url);
return (await response.json()) as User;
}
复制代码
在上面的代码中,编译器认为请求将返回一个带有 name
和email
属性的 JSONUser
对象。如果结果不是这样,将在生产中出现bug。但不幸的是,这些bug只能在运行时找到原因。
我们可以定义一个模式,该zod
模式可以在运行时进行验证。
让我们看看使用zod
重构后的代码:
const UserSchema = z.object({
name: z.string(),
email: z.string(),
});
async function fetchUser(id: string) {
const url = `/users/${id}`;
const response = await fetch(url);
// ✅如果校验不通过,可以通过日志抛出错误。
return UserSchema.parse(await response.json());
}
复制代码
我们可以选择如何处理错误。在上面的示例中,UserSchema.parse
将在运行时引发错误。
我们也可以选择不使用safeParse
方法抛出错误。它仅适合在日志记录问题而不会破坏用户体验。
Zod 非常强大,我们还可以使用z.infer
. 我们可以在整个代码中使用该方法。
const UserSchema = z.object({
name: z.string(),
email: z.string(),
});
export type User = z.infer<typeof UserSchema>;
复制代码
总而言之,它是一个强大的库。
zod
的一些其他优点:
- 它很小:8kb 缩小 + 压缩
- 零依赖
- 不可变
- 简洁、可链接的界面
- 功能方法
- 也适用于纯 JavaScript!你不需要使用 TypeScript。
zod
注意事项:
- TypeScript 4.1 及更高版本
- 启用严格模式
zod
安装:
npm install --save-dev zod
复制代码
2、tiny-invariant
在 TypeScript 的严格模式下,如果您不进行验空检查,会出现bug。 为了避免bug,有原生的!操作方法。
让我们看一个例子:
interface User {
name?: string;
email?: string;
}
const u: User = { name: 'Joe', email: 'joe@no-reply.com'};
// ❌ Error: 对象可能是 'undefined'
console.log(u.name.toUpperCase());
// ✅ Compiles
console.log(u.name!.toUpperCase());
复制代码
以上做法不太完美,因为有时这些开发人员的假设判断可能是错误的。
通过使用tiny-invariant
,您可以在断言不正确时在运行时抛出异常,并在 Sentry
或任何其他提供程序上捕获该异常。这将增加您对代码的信心并检测任何不一致之处。
import invariant from 'tiny-invariant';
interface User {
name?: string;
email?: string;
}
const u: User = { name: 'Joe', email: 'joe@no-reply.com'};
invariant(u.name, 'Name should not be null for this scenario')
// ✅ Compiles without the need of `!`
console.log(u.name.toUpperCase());
复制代码
代码更有弹性,我们可以清除很多冗余if
语句。
这个包是最小的,如果你愿意,你可以选择实现你自己的invariant
功能。
tiny-invariant
注意事项:
- 严格模式 (否则毫无意义)
tiny-invariant
安装:
npm install --save-dev tiny-invariant
复制代码
3、type-fest
TypeScript 最强大的功能之一是映射类型。
TypeScript 附带了一些方法,但是这些方法是有限的,并且只是作为一个起点。因此,可以肯定的是,您的代码中有一些公共方法。可能在一个utils.d.ts
文件中,你可能会从一个项目带到另一个项目的地方。这绝对没问题,但是,还有其他方法可以解决该问题。
您可以使用一些类型的库。例如:ts-toolbet
。它提供了久经考验的类型,可以减少您花在编写新映射上的时间。
通过查看 npm 趋势,您可以发现该type-fest
领域是如何占据主导地位的。通过npmtrends可以看到:
让我们看一个例子。TypeScript 原生的Optional
方法非常有限。它只是让我们将所有属性标记为可选。它缺乏细节。
让我们看看type-fest
关于该用例的内容:
import { type MarkOptional, type OptionalKeys } from 'ts-essentials';
interface User {
name: string;
email: string;
}
// 原生方法:所有的属性都是可选的
type PartialUser = Partial<User>;
// Result:
// {
// name?: string;
// email?: string;
}
// 💪 仅支持选中的属性是可选的
type PartialUserEmail = MarkOptional<User, 'email'>;
// Result:
// {
// name: string
// email?: string;
}
// 💪 从类型中获取可选的key
type PartialKeys = OptionalKeys<PartialUserEmail>;
// Result:
// email
复制代码
我们可以看到实现这一目标需要多么强大和多么少的代码。由于所有类型都在编译时被删除,这不会增加你的包大小。
请注意,所有这些类型的库都有一些要求和限制。因此,您可能会被迫更新到较新的 TypeScript 版本或要求您的代码在严格模式下.
type-fest
的要求
- TypeScript 4.7 及更高版本
- 严格模式
type-fest
安装:
npm install --save-dev type-fest
复制代码
4、ts-morph
在许多不同的场景中,对代码执行静态分析很有用。你可以使用jscodeshift
,甚至babel
实现。但是,对类型有更多的了解可能会很方便。
为此,您只能使用 TypeScript 编译器,它可以转化为陡峭的学习曲线。这个ts-morph
项目很久以前就有了。它提供了一种更简单的方式来以编程方式执行和操作 TypeScript 代码。
它是如何做到这一点的?
- 通过提供一些围绕编译器 API 的包装器。
- 允许回退到编译器 API
- 首先在内存中进行所有更改,并且仅在收到指示时才发送到代码
让我们检查一个简单的示例,其中将检查枚举并在它确实存在的情况下对其进行更改。
安装非常简单:
npm install --save-dev ts-morph
复制代码
我们可以创建我们的example.ts
文件来运行我们的代码。
import { Project } from 'ts-morph';
const project = new Project();
const OLD_FUNCTION_NAME = 'addingNumbers';
const NEW_FUNCTION_NAME = 'sum'
// ✅ 对位置的范围更改
project.addSourceFilesAtPaths('src/**/*.ts');
project.getSourceFiles().forEach((sourceFile) => {
// ✅ 获取要检查的目标
const functions = sourceFile.getFunctions();
// ✅ 过滤所需要的目标
functions.forEach((item) => {
if (item.getName() === OLD_FUNCTION_NAME) {
// ✅ 重命名
item.rename(NEW_FUNCTION_NAME);
}
});
// ✅ 保存
sourceFile.save();
});
复制代码
然后我们只需要运行它:
npx ts-node example.ts
复制代码
5、Type-docs
文档是构建 API 时的一个重要方面。它可以帮助其他开发人员快速掌握您的应用程序正在公开的内容。通常每种语言都有自己的构建文档的过程。
使用 TypeScript,没有内置工具,这就是TypeDoc
它诞生的原因。它使用代码注释以 HTML 或 JSON 格式构建文档。它是可扩展的并且支持多种配置。
该工具附带方便的文档,可在typedoc.org找到。有一些简单的例子可以用来学习掌握工具。
让我们看一个如何为方法注释注释的示例:
/**
* Calculates the square root of a number.
*
* @param x the number to calculate the root of.
* @returns the square root if `x` is non-negative or `NaN` if `x` is negative.
*/
export function sqrt(x: number): number {
return Math.sqrt(x);
}
复制代码
结果如下:
你会得到很多开箱即用的东西:
- 干净的界面
- 面包屑
- 侧向导航
- 易于定制的 CSS ,可以根据您的喜好对其进行定制
Type-docs
安装
npm install typedoc --save-dev
复制代码
要生成文档,需要了解tsconfig.json
配置文件。
typedoc src/index.ts
复制代码
您还可以定义多个入口
typedoc src/package1/index.ts src/package2/index.ts
复制代码
你可以传递一个文件夹,而不是一个文件,TypeDoc 将使用entryPointStrategy
它来查找index
文件。
此策略只需运行就可以为工作区生成文档:
// ✅ 将去文件夹中寻找index.ts文件
typedoc --entryPointStrategy packages .
复制代码
结束语:
这五个不同的 TypeScript
库中的任何一个都可以提高任何项目的开发效率。