TypeScript快速入门:30分钟上手指南

模型调用员
2025-12-13 18:30
阅读 242

上周五下班前,我们组新来的产品经理又丢了个“小需求”过来:“下周三要上线一个内部数据看板,前端用 React,后端接口 Springboot 已经写好了,你随便搞搞就行。”

我盯着 Slack 上那句“随便搞搞”,默默喝了口枸杞水——这年头,“随便搞搞”往往意味着通宵改 Bug。好在我司是国企,双休雷打不动,加班?不存在的。但为了保住周末的躺平时光,我决定这次直接上 TypeScript,少踩点坑,早点下班。

其实我一直是个 JavaScript 的老用户,以前觉得 TS 就是加点类型注解,多此一举。直到去年双11期间,我用纯 JS 写了个爬虫脚本(对,别笑,国企也得抓点竞品数据),结果因为一个 undefined 字段导致整个流程崩了,运维大哥半夜打电话问我:“兄弟,你这脚本是不是把对方服务器 IP 给抓没了?” 那时候我才意识到:动态类型一时爽,运行报错火葬场


为什么现在必须学 TypeScript?

先说背景:我们团队目前主力栈是 React + Springboot,偶尔会用 Go 写些微服务或爬虫。最近领导在推“工程化规范”,要求所有新项目必须带类型系统。我一开始还嘀咕:“Go 不是有强类型吗?为啥前端也要卷?” 但实测下来,TS 真香!

特别是和 Springboot 对接时,后端返回的 JSON 结构一旦变动,JS 里根本不知道字段没了,直到 UI 渲染出 undefined 才发现。而 TS 能在编译阶段就告诉你:“嘿,这个字段压根不存在!” —— 这不比线上炸了再背锅强?


快速上手:30 分钟搞定核心概念

我不是那种从零讲起的教程博主,咱们直接上干货。以下内容,我在公司 Mac 上实测过(Windows?那是我用来跑 IE 测试的备用机,别提了)。

1. 安装 & 初始化

npm install -g typescript
tsc --init

生成的 tsconfig.json 是你的命根子。我建议至少开启这几个选项:

{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "esModuleInterop": true,
    "jsx": "react-jsx"
  }
}

strict: true 是底线,不然你写的就是 “anyScript”,白搭。


2. 类型注解 vs 接口 vs 类型别名

很多人卡在这儿。举个实际例子:假设 Springboot 返回一个用户列表:

// Springboot Controller
@GetMapping("/users")
public List<User> getUsers() { ... }

// User.java
public class User {
  private Long id;
  private String name;
  private Boolean active;
}

对应到前端,你怎么定义这个结构?

// 方式一:interface(推荐用于对象形状)
interface User {
  id: number;
  name: string;
  active: boolean;
}

// 方式二:type alias(适合联合类型、元组等)
type User = {
  id: number;
  name: string;
  active: boolean;
};

区别在哪?

  • interface 可以合并(比如不同模块扩展同一个接口),更适合描述“对象契约”。
  • type 更灵活,能表示原始类型、联合类型(string | number)、映射类型等。

在我们 React 项目里,API 响应体一律用 interface,函数参数用 type,各司其职。


3. 和 React 配合:函数组件 + Hooks

以前写 React 经常遇到这种问题:

function UserProfile({ userId }) {
  // userId 到底是 string 还是 number?没人知道
}

现在用 TS,直接约束:

interface UserProfileProps {
  userId: string;
  showAdminPanel?: boolean; // 可选属性
}

const UserProfile: React.FC<UserProfileProps> = ({ userId, showAdminPanel = false }) => {
  // ✅ 类型安全!
  return <div>User ID: {userId}</div>;
};

更狠的是配合 useEffect 和异步请求:

const [user, setUser] = useState<User | null>(null);

useEffect(() => {
  fetch(`/api/users/${userId}`)
    .then(res => res.json())
    .then(data => {
      // 如果 data 不符合 User 结构,TS 会报错!
      setUser(data as User);
    });
}, [userId]);

当然,生产环境我会用 zodio-ts 做运行时校验,但 TS 至少能防住 80% 的低级错误。


4. 实战:用 TS 写个简单爬虫(对,前端也能爬)

别惊讶,我们偶尔要用 Puppeteer 抓点公开数据做分析。以前用 JS 写,经常因为页面结构变了导致字段为空。现在:

interface Product {
  title: string;
  price: number;
  rating: number | null; // 有些商品没评分
}

async function scrapeProducts(): Promise<Product[]> {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example-shop.com');

  const products = await page.evaluate(() => {
    return Array.from(document.querySelectorAll('.product')).map(el => ({
      title: el.querySelector('.title')?.textContent ?? '',
      price: parseFloat(el.querySelector('.price')?.textContent ?? '0'),
      rating: el.querySelector('.rating')
        ? parseFloat(el.querySelector('.rating')!.textContent)
        : null
    }));
  });

  await browser.close();
  return products;
}

注意这里用了 ??(空值合并)和 !(断言非空),都是 TS 提供的安全操作符。以前这种地方动不动就 Cannot read property 'textContent' of null,现在 IDE 直接标红,根本跑不起来。


5. 和 Go / Springboot 协同开发的小技巧

我们后端用 Springboot,有时候字段命名是 camelCase,有时候是 snake_case(别问,问就是历史遗留)。TS 里可以用映射类型自动转换:

// 后端返回 snake_case
interface RawUser {
  user_id: number;
  full_name: string;
}

// 前端想要 camelCase
interface User {
  userId: number;
  fullName: string;
}

// 自动转换函数(配合 keyof)
function snakeToCamel<T extends Record<string, any>>(obj: T): any {
  const newObj: Record<string, any> = {};
  for (const key in obj) {
    const camelKey = key.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
    newObj[camelKey] = obj[key];
  }
  return newObj as any;
}

虽然有点 hack,但在对接老旧接口时救命用。


踩过的坑 & 避坑指南

  1. 不要滥用 any
    我见过同事为了快,满屏 any,结果 TS 形同虚设。记住:any 是技术债,不是捷径。

  2. .d.ts 文件怎么写?
    如果引入第三方库没类型声明,自己写个 types/mylib.d.ts

    declare module 'mylib' {
      export function doSomething(input: string): number;
    }
    
  3. React 中 event 类型别乱猜
    正确姿势:

    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
      console.log(e.target.value);
    };
    

效果如何?

自从在新项目全面启用 TS,我们的线上 JS 错误率下降了 67%(数据来自 Sentry)。上周三那个“随便搞搞”的看板,周二下午就交付了,周五准点下班去吃火锅。

更重要的是,当产品经理说“能不能加个筛选功能”,我不再心慌——因为我知道,只要改接口定义,TS 会自动告诉我哪些组件需要调整,不用靠肉眼 grep 全局。


最后说两句

TypeScript 不是银弹,但它是我近年来用过最值得投入学习成本的前端工具之一。尤其在中大型项目、多人协作、前后端联调场景下,它的价值远超“多写几行类型”。

而且,作为国企程序员,我图啥?不就图个稳定、少背锅、准时下班嘛。TS 帮我做到了。

所以,别再犹豫了。花 30 分钟,把你的下一个 React 项目改成 TS。相信我,未来的你会感谢现在的自己——尤其是在周五下午 5:50,别人还在修 Bug,你已经拎包走人的时候。

P.S. 我们团队最近也在用 Go 重构一些数据管道,如果你对 TS + Go 混合架构感兴趣,评论区留言,下次聊聊怎么用 Go 写爬虫,TS 做前端展示,Springboot 当中间层——一套组合拳,打遍内部系统无敌手 😎

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝