从
console.log()到类型安全,我用 TS 把 Bug 拒之门外
🚀 开篇:你有没有被 JavaScript "背刺"过?
想象一下这个场景:
你信心满满地提交了 PR,CI 流水线绿得发亮。
结果上线 5 分钟后,用户反馈:"点按钮没反应!"
你打开控制台一看------
javascript
Uncaught TypeError: Cannot read property 'map' of undefined
......原来是你把 users 写成了 user,但 JS 并没有在你敲错的那一刻提醒你。
JavaScript 是个自由奔放的朋友,但它不负责帮你兜底。
而 TypeScript?它是那个在你写错时就拍桌子说:"兄弟,这不行!"的严谨搭档。
💡 TypeScript 是什么?一句话说清
TypeScript = JavaScript + 静态类型系统 + 编译时检查 + 更聪明的 IDE
它不是一门新语言,而是 JavaScript 的"超集"(Superset)------所有合法的 JS 代码都是合法的 TS 代码。
但反过来,TS 能在你写代码的时候就揪出潜在问题,而不是等到用户点击才崩溃。
🛠️ 安装?一行命令搞定!
npm install -g typescript
然后你就可以用 tsc 编译 .ts 文件,或者直接用 Vite / Create React App 等现代工具链,它们早已原生支持 TS。
✨ TypeScript 的五大"超能力"
1️⃣ 静态类型:让变量"有身份"
ini
let name: string = "掘金读者";
name = 123; // ❌ 编译时报错!
不再是"万物皆可赋值",每个变量都有明确的身份卡。
2️⃣ 边写边查错:IDE 实时预警
VS Code + TS = 黄金搭档。
你刚打错一个属性名,红色波浪线立刻出现:"亲,这个对象没有 useName,只有 username 哦~"
3️⃣ 编译时拦截 Bug,不让错误上生产
JS 是"运行时才知道错",TS 是"写完就告诉你错"。
省下的不只是 debug 时间,更是半夜被 PagerDuty 叫醒的噩梦。
4️⃣ 智能提示 & 自动文档
接口定义即文档:
typescript
interface Todo {
id: number;
title: string;
completed: boolean;
}
当你在组件里用 todo. 时,IDE 自动弹出 id、title、completed ------ 不用翻文档,代码自己会说话!
5️️⃣ 清理"僵尸代码"
TS 会警告你:"这个变量声明了但从没用过!"
包括那些藏在角落的 console.log('调试中...') ------ 重构时再也不怕残留垃圾代码。
🧪 实战:用 TS + Zustand 打造一个"坚不可摧"的 TodoList
我们不用 Redux(太重),也不用手搓 useState(太乱)。
Zustand + TypeScript = 轻量、简洁、类型安全的状态管理!
📦 状态定义:接口先行
typescript
// types/todo.ts
export interface Todo {
id: number;
title: string;
completed: boolean;
}
🧠 自定义 Hook:useTodos
ini
// hooks/useTodos.ts
import { useState, useEffect } from 'react';
import type { Todo } from '../types/todo';
export function useTodos() {
const [todos, setTodos] = useState<Todo[]>(() => getStorage('todos', []));
useEffect(() => {
setStorage('todos', todos);
}, [todos]);
const addTodo = (title: string) => {
const newTodo: Todo = {
id: Date.now(),
title,
completed: false
};
setTodos([...todos, newTodo]);
};
const toggleTodo = (id: number) => {
setTodos(todos.map(t => t.id === id ? { ...t, completed: !t.completed } : t));
};
const removeTodo = (id: number) => {
setTodos(todos.filter(t => t.id !== id));
};
return { todos, addTodo, toggleTodo, removeTodo };
}
🔍 注意:所有函数参数、返回值、状态都带类型!
即使半年后回来看代码,也能秒懂数据结构。
🎨 组件 Props 也用接口约束
typescript
// components/TodoInput.tsx
interface Props {
onAdd: (title: string) => void;
}
const TodoInput: React.FC<Props> = ({ onAdd }) => {
// ...
}
父子组件传参?TS 保证你不会传错类型、漏掉属性!
😂 对比:JS vs TS 的"加法"哲学
csharp
// JavaScript:自由但危险
function add(a, b) {
return a + b; // 可能是 15,也可能是 "105"!
}
add(10, "5"); // 输出 "105" ------ 你懵了?
typescript
// TypeScript:明确且安全
function add(a: number, b: number): number {
return a + b;
}
add(10, "5"); // ❌ 类型错误!编译不过!
TS 不是限制你,而是保护你。
🧩 TS 的类型魔法箱(简要彩蛋)
- 联合类型 :
type ID = string | number; - 元组 :
let user: [number, string] = [1, "Tom"]; - 枚举 :
enum Status { Pending, Success, Failed } - 泛型 :
function getStorage<T>(key: string, def: T): T - unknown vs any :
unknown更安全,强制类型检查!
初学者别怕
any,它是"救命稻草",但别让它变成"懒人借口"。
🌟 结语:TS 不是负担,而是生产力加速器
有人说:"TS 学习成本高。"
但我想说:调试一个线上 Bug 的成本,远高于写一个类型注解。
大型项目、团队协作、长期维护 ------ TS 就是你的"代码保险"。
用 JS 写代码,靠运气;用 TS 写代码,靠实力。
所以,别再让 undefined is not a function 成为你项目的日常梗了。
拥抱 TypeScript,让你的代码既健壮又优雅。
✅ 今日行动建议:
- 在现有项目中新建一个
.ts文件试试- 给你的 React 组件 Props 加上
interface- 把
useState的初始值加上泛型<T>小步快跑,渐进式升级,你离"类型安全"只差一次尝试。