5 个 TypeScript 库来改进你的代码

3,752 阅读6分钟

我正在参加「掘金·启航计划」!

1_C24eNZfu0CT5fSTBt6IugA.png

在过去的几年里,TypeScript 语言除了增长用户之外几乎什么都没做。它已被许多 Web 开发人员评为最喜欢的语言。使用纯JavaScript 代码的前端工作变得越来越少。

但是,有时 TypeScript 并没有充分发挥其潜力。导致过多或使用过多any是最常见的错误之一。

在本文中,我们将看到5 个 TypeScript 库,这些库将增强您的 TypeScript 体验并增加您对其静态类型的信心。这些最小的库将提高开发人员的开发效率。

1、zod

TypeScript 的薄弱环节是仅在编译时验证。一旦它被解析和构建,所有类型都被删除。在以下情况下,这可能会导致出现一些错误:

  • 编译器以一些假设信任开发人员(开发人员使用anyts-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;   
}

在上面的代码中,编译器认为请求将返回一个带有 nameemail属性的 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可以看到:

截屏2022-09-21 下午3.31.59.png

让我们看一个例子。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);                                                       
}

结果如下:

截屏2022-09-21 下午6.54.48.png

你会得到很多开箱即用的东西:

  • 干净的界面
  • 面包屑
  • 侧向导航
  • 易于定制的 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 库中的任何一个都可以提高任何项目的开发效率。