每位前端开发者都应该掌握的 5 个 TypeScript 技巧

AI 概述
本文分享五个实用TypeScript开发技巧:用as const精准收窄字面量类型,借助判别联合类型规范多状态数据,用satisfies兼顾类型校验与精准推断,利用模板字面量类型约束字符串格式,掌握常用内置工具类型并避开常见编码陷阱,助力开发者精简代码、减少错误、提升项目类型安全性。
目录
文章目录隐藏
  1. 1. 使用 as const 收窄类型
  2. 2. 判别联合类型
  3. 3. 使用 satisfies 替代类型注解
  4. 4. 模板字面量类型
  5. 5. 必备的工具类型与常见 TypeScript 陷阱
  6. 结语

每位前端开发者都应该掌握的 5 个 TypeScript 技巧

当大多数前端开发者开始使用 TypeScript 时,常常会感觉我们在不断地与类型系统作斗争 —— 到处都是错误、红色波浪线,以及一开始看起来毫无意义的规则。但一旦你理解了一些关键模式,一切都会改变。TypeScript 不再是一个问题,而开始成为你最大的编码优势。

在这篇文章中,我将分享 5 个实用的 TypeScript 技巧,它们可以彻底改变你编写和理解代码的方式。

让我们从第一个技巧开始。

1. 使用 as const 收窄类型

让我们从一个几乎让所有 TypeScript 初学者感到困惑的问题开始。

TypeScript 有时表现得像一个过度保护的家长。即使你明确地写了一个值,比如 “GET”,它仍然只把它当作一个普通的 string,而不是精确的值 “GET”。

问题也正是从这里开始的。

想象一下你对某人说:

“我要带一个红色的球。”

但对方回答:

“好的……你要带一个球。”

这正是 TypeScript 的默认行为。它忽略了“红色”这一部分,只记住了“球”。

但有时候,你的函数只接受红色或蓝色的球——而不是任意的球。

因此,当 TypeScript 把 “GET” 仅仅当作 “string” 时,你的函数可能会报错。

问题

function makeRequest(method: "GET" | "POST") {
  console.log("Request method:", method);
}
const request = {
  method: "GET"
};
makeRequest(request.method); 
// ❌ Error: Type 'string' is not assignable to type '"GET" | "POST"'

使用 as const 收窄类型

为什么会出现这个错误?

因为 TypeScript 将 “GET” 扩宽成了一个通用的 string。它忘记了这个值实际上是一个特定的 “GET”。

解决方案 —— as const

我们告诉 TypeScript:

“不要对它进行泛化。按原样精确对待它。”

const request = {
  method: "GET"
} as const;
makeRequest(request.method);
// ✅ Works perfectly

每位前端开发者都应该掌握的 5 个 TypeScript 技巧

现在 TypeScript 明白了:

  • 这个值是固定的
  • 它是只读的
  • 它就是精确的 “GET” —— 而不是任意的 string

as const 实际上做了什么?

当你添加 as const 时,TypeScript:

1.锁定值(只读)

锁定值(只读)

2.保留精确的字面量类型

3.防止被扩宽为 string、number 等类型

"GET" → 保持 "GET"
42 → 保持 42
true → 保持 true

使用案例

这在配置文件、路由或常量数据中非常有用。

const routes = {
  home: "/",
  about: "/about",
  contact: "/contact"
} as const;

现在 TypeScript 会自动知道这些精确的值。

你甚至可以从中生成类型:

type Route = typeof routes[keyof typeof routes];
// "/" | "/about" | "/contact"

每位前端开发者都应该掌握的 5 个 TypeScript 技巧

  • 不需要手动定义类型;
  • 没有重复;
  • 一切保持同步。

何时应该使用它

在以下情况下使用as const

  • 定义配置对象时;
  • API 方法常量;
  • 路由;
  • 状态码;
  • action 类型(Redux 等)。

本质上就是:任何值不应该改变且必须保持精确的地方

2. 判别联合类型

这是 TypeScript 中最强大的模式之一,同时也是初学者最容易误解的之一。

它解决了一个非常常见的真实问题:处理那些看起来相似,但会根据自身状态表现出不同行为的对象。

例如:

  • loading 状态;
  • success 状态;
  • error 状态。

想象一个交通灯,它有 3 种状态:

  • 红灯 → 停止;
  • 黄灯 → 等待;
  • 绿灯 → 通行。

你不会用同样的方式对待它们。

你不会说:

“也许停……也许走……也许等……”

每种状态都有明确的身份。

这正是 TypeScript 希望你的对象具备的方式。

初学者常犯的错误

大多数初学者会像这样创建一个巨大的接口:

interface ApiResponse {
  status: string;
  data?: string;
  error?: string;
}

看起来很简单,但它会引发混乱。

现在 TypeScript 无法知道:

  • 什么时候 data 存在
  • 什么时候 error 存在
  • 哪些是可以安全使用的

你可能会在错误状态下误访问 data。

这种方式下 TypeScript 无法很好地保护你。

更好的方式 —— 判别联合类型

与其使用一个混乱的接口,不如创建独立的状态。

interface LoadingState {
  status: "loading";
}
interface SuccessState {
  status: "success";
  data: string;
}
interface ErrorState {
  status: "error";
  error: string;
}
type ApiResponse = LoadingState | SuccessState | ErrorState;

现在每种状态都是清晰且可预测的。

TypeScript 是如何变得“智能”的?

function handleResponse(response: ApiResponse) {
  if (response.status === "success") {
    console.log(response.data);
     // ✅ TypeScript 知道 data 存在
  }
  if (response.status === "error") {
    console.log(response.error);
    // ✅ TypeScript 知道 error 存在
  }
}

TypeScript 会自动理解:

  • 在 success 中 → data 可用;
  • 在 error 中 → error 可用;
  • 在 loading 中 → 两者都不存在。

没有混乱。

不需要猜测。

没有不安全的代码。

为什么这种模式在实际应用中很强大

你会在很多地方使用它:

  • API 响应;
  • 认证状态;
  • UI 状态(loading、empty、success、failure);
  • reducer(Redux、Zustand 等);
  • 支付状态;
  • 表单校验流程。

这种模式会让你的应用变得:

  • 更安全;
  • 更容易调试;
  • 更容易扩展。

而 TypeScript 会成为你的助手,而不是你的对手。

3. 使用 satisfies 替代类型注解

这是 TypeScript 中一个较新的特性,一旦你理解了它,你就会在各处使用它。

它解决了一个微妙但令人沮丧的问题:在不丢失对象具体细节的情况下,对对象的结构进行校验。

想象一位老师在检查你的作业。

他们不会重写你的答案。他们只是检查:

“是的,这符合规则。”

这正是 satisfies 所做的事情。

它会检查你的对象是否符合所需的结构,但不会改变你最初写下的内容。

普通类型注解的问题

当你这样写时:

type ButtonVariant = "primary" | "secondary";
const button: ButtonVariant = "primary";

TypeScript 只会记住:

这是允许的变体之一

但如果你使用对象:

type ButtonConfig = {
  variant: "primary" | "secondary";
};
const config: ButtonConfig = {
  variant: "primary"
};

TypeScript 会发生类型扩宽。

它关注的是匹配类型,而不是保留精确的字面量细节。

更好的方式 —— satisfies

type ButtonConfig = {
  variant: "primary" | "secondary";
};
const config = {
  variant: "primary"
} satisfies ButtonConfig;

现在会发生两件事:

  1. TypeScript 会检查该对象是否符合 ButtonConfig
  2. 它仍然会记住精确的值 “primary”。

因此你获得:

  • 校验;
  • 安全性;
  • 精确性。

它在什么情况下会变得非常有用

当处理配置对象、路由或映射时。

例如:

type Routes = Record<string, string>;
const routes = {
  home: "/",
  about: "/about",
  contact: "/contact"
} satisfies Routes;

现在 TypeScript:

  • 确保所有值都是 string;
  • 保留精确的键名;
  • 保留字面量类型。

防止拼写错误

satisfies 可以捕获那些简单类型注解可能无法清晰提示的错误。

type ButtonConfig = {
  variant: "primary" | "secondary";
};
const config = {
  varient: "primary" // ❌ 拼写错误
} satisfies ButtonConfig;

每位前端开发者都应该掌握的 5 个 TypeScript 技巧

TypeScript 会立即标记:

缺少属性 ‘variant’

这可以防止配置中出现悄无声息的 bug。

为什么开发者喜欢它

因为它同时具备两方面的优势:

  • 严格的结构校验;
  • 精确的字面量推断;
  • 更安全的配置文件;
  • 更好的自动补全;
  • 避免不必要的类型扩宽。

尤其适用于:

  • 设计系统配置;
  • 路由定义;
  • feature flags;
  • 常量映射;
  • UI 组件变体。

4. 模板字面量类型

大多数初学者认为 TypeScript 只适用于数字、对象和函数。

但其实 TypeScript 也可以控制字符串应该是什么样子。

是的,甚至字符串格式也可以是类型安全的。

想象你的老师说:

“你只能按照这种格式写答案:数字 + 单位。”

这意味着:

  • ✅ 10px
  • ✅ 2rem
  • ❌ 10
  • ❌ px

模板字面量类型允许 TypeScript 强制执行这样的规则。

它是如何工作的

你可以使用反引号组合类型:

type CSSUnit = "px" | "rem" | "em";
type Size = `${number}${CSSUnit}`;

现在只允许符合模式的值。

示例 —— CSS 值:

function setWidth(size: Size) {
  console.log(size);
}
setWidth("20px");  // ✅ 合法
setWidth("2rem");  // ✅ 合法
setWidth("20");    // ❌ 错误
setWidth("20pt");  // ❌ 不支持的单位

每位前端开发者都应该掌握的 5 个 TypeScript 技巧

TypeScript 会检查格式,而不仅仅是类型。

这可以在运行时之前防止 bug。

真实使用场景 —— API 接口

你可以安全地生成结构化字符串。

type Method = "GET" | "POST";
type Version = "v1" | "v2";
type Resource = "users" | "posts";
type ApiEndpoint = `${Method}/${Version}/${Resource}`;

现在:

const endpoint: ApiEndpoint = "GET/v1/users"; // ✅ 合法
const wrong: ApiEndpoint = "FETCH/v1/users";  // ❌ 不合法

每位前端开发者都应该掌握的 5 个 TypeScript 技巧

你是在类型层面定义 API 规则。

不会有无效的 API 接口漏过。

为什么这很强大

因为应用中的许多 bug 都来自错误的字符串格式:

  • CSS 值;
  • URL;
  • API 路由;
  • class 名;
  • ID;
  • 事件名。

模板字面量类型为你提供:

  • 格式安全;
  • 自动补全;
  • 零运行时校验;
  • 更少的生产环境 bug。

你会在真实项目中使用它的地方

  • 设计系统;
  • API 客户端;
  • 路由生成器;
  • 动态 class 名;
  • 基于配置的 UI。

对于一些大型团队,命名模式会显得非常重要,这个时候模板字面量类型就尤为有用。

5. 必备的工具类型与常见 TypeScript 陷阱

这个最后的技巧就像一个工具箱。

TypeScript 已经为你提供了许多内置的辅助工具,但大多数初学者要么:

  • 不知道它们的存在;
  • 误解了它们的行为。

这就会导致 bug、困惑以及混乱的类型。

让我们把它们简单拆解一下。

你必须了解的工具类型

可以把工具类型看作是对类型进行编辑的工具。

你不需要重写一切,只需调整你需要的部分。

1)Required —— 让所有属性变为必填

type User = {
  name?: string;
  age?: number;
};
type RequiredUser = Required<User>;

现在:

  • name → 必填;
  • age → 必填。

每位前端开发者都应该掌握的 5 个 TypeScript 技巧

适用于以下情况:

  • 在保存之前数据必须完整;
  • 表单提交校验;
  • API 请求体准备。

2)Partial —— 让所有属性变为可选

type User = {
  name: string;
  age: number;
};
type UpdateUser = Partial<User>;

每位前端开发者都应该掌握的 5 个 TypeScript 技巧

现在你可以只更新一个字段:

{ name: "Asheesh" } // 合法

非常适用于:

  • 更新 API;
  • patch 请求;
  • 表单编辑。

3)Pick<T, Keys> —— 只选择你需要的部分

type User = {
  id: number;
  name: string;
  email: string;
};
type UserPreview = Pick<User, "name" | "email">;

适用于以下情况:

  • 在 UI 中展示有限的数据
  • 避免过度获取数据
  • 创建轻量对象

4)Omit<T, Keys> —— 移除你不需要的部分

type User = {
  id: number;
  name: string;
  email: string;
};
type UserWithoutId = Omit<User, "id">;

适用于以下情况:

  • 移除敏感数据;
  • 公共 API 响应;
  • 仅用于 UI 的数据模型。

常见的 TypeScript“陷阱”

这些问题甚至会让有经验的开发者感到困惑。

1)“空对象”陷阱

很多人会这样写:

const obj: {} = {};

他们认为这表示“空对象”。

但它实际上表示:

任何非 null 或 undefined 的值

所以这是合法的 😳

const obj: {} = "hello";
const obj2: {} = 42;

这很危险。

正确的写法:

const obj: Record<string, never> = {};

现在它真正表示:

  • 不允许任何属性
  • 严格的空对象

2)可选链的陷阱

当你使用 ?. 时,TypeScript 会引入 undefined。

const name = user?.name;

类型会变成:

string | undefined

因此下面的写法会报错:

name.toUpperCase(); // ❌ 可能是 undefined

你必须进行处理:

if (name) {
  name.toUpperCase(); // ✅ 安全
}

或者:

const safeName = name ?? "Guest";

工具类型就像 LEGO 工具。

你不需要每次都构建一个全新的玩具。你可以:

  • 移除部分;
  • 添加部分;
  • 重塑结构。

而 TypeScript 已经为你提供了这些工具,你只需要使用它们。

为什么这在实际项目中很重要

这些工具可以帮助你:

  • 避免重写类型;
  • 保持 API 类型清晰;
  • 减少重复;
  • 让大型应用更易于管理。

结语

TypeScript 在一开始可能会让人感觉严格、困惑,甚至令人沮丧。我也经历过。但一旦你理解了一些核心模式,它就不再像是一个阻碍,而开始成为一个真正保护并引导你代码的工具。

这五个技巧表面上看很简单,但在真实项目中会带来巨大的变化:

  • 更清晰的逻辑;
  • 更少的 bug;
  • 以及在编写代码时更强的信心。

以上关于每位前端开发者都应该掌握的 5 个 TypeScript 技巧的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » 每位前端开发者都应该掌握的 5 个 TypeScript 技巧

发表回复