前端小白的 React + TypeScript 奇幻冒险之旅 🚀

138 阅读7分钟

为什么选择 React + TypeScript 🤔

image.png

想象一下这个场景:你辛辛苦苦写了一个登录功能,测试的时候一切正常,上线后突然收到用户反馈 ——"点登录没反应啊!" 排查了半天发现,后端返回的用户信息里,isLogin字段有时候是布尔值true,有时候是字符串"true",而你写的判断逻辑是if (user.isLogin)... 这种因为类型混乱导致的 Bug,在 JavaScript 开发中简直像家常便饭 🍚

JavaScript 作为一门弱类型语言,就像个调皮的孩子 —— 你让它拿个苹果,它可能给你带个橙子回来,还理直气壮地说 "反正都是水果嘛~" 而当项目规模越来越大,这种 "不拘小节" 就会变成灾难:函数参数传错类型、对象属性拼写错误、数组里混进奇怪的值... 调试这些问题的时间,够你喝十杯奶茶了 🥤

这时候,React + TypeScript 的组合就像给代码装上了 "安全气囊" 和 "导航系统":

  • React 帮你把 UI 拆成一个个可复用的组件,让界面开发像搭积木一样简单 🧱

  • TypeScript 则给 JavaScript 加上类型约束,在你写代码的时候就提前报错,把 Bug 扼杀在摇篮里

对于大型项目来说,这对组合堪称 "黄金搭档"—— 微软爸爸开发的 TypeScript,配上 Facebook 打造的 React,就像肯德基的炸鸡配可乐,绝配!

React 与 TypeScript 初相识 👋

image.png

React:构建用户界面的神器 ✨

React 是个啥?简单说就是个用来写网页界面的 JavaScript 库。它最核心的概念是 "组件"—— 你可以把组件理解成一个函数,接收一些参数(props),然后返回一段描述界面的代码(JSX)。

比如一个最简单的组件长这样:

// 这就是一个React组件
function Hello() {
  return <h1>Hello React! 👋</h1>;
}

就像乐高积木一样,你可以把这些小组件组合起来,搭建出复杂的页面。而且 React 采用 "单向数据流",数据变化时界面会自动更新,再也不用手动操作 DOM 了,简直是前端开发者的福音 🙏

TypeScript:JavaScript 的超强升级版 🦸‍♂️

TypeScript(简称 TS)是微软开发的 JavaScript 超集 —— 啥意思?就是 TS 完全兼容 JS 的语法,你可以把 JS 代码直接改成 TS 代码,它照样能跑。但 TS 多了个大杀器:类型约束

比如在 JS 里,你可以这么写:

let age = 18;
age = "十八"; // 没问题,JS默默接受了

但在 TS 里,这就会直接报错:

let age: number = 18;
age = "十八"; // 红波浪线警告!Type 'string' is not assignable to type 'number'

就像给变量贴上了标签,"这个只能装数字,那个只能装字符串",从此代码变得规矩起来。而且 TS 的类型检查是在编译阶段进行的,最终会转成纯 JS 运行,不影响浏览器兼容性,是不是很贴心?

React + TypeScript 开发环境搭建 🛠️

image.png

准备工作 📋

首先得确保你电脑上装了 Node.js 和 npm(一般装 Node.js 会自带 npm)。检查一下:

node -v  # 输出版本号就说明装好了,比如 v18.16.0
npm -v   # 比如 9.5.1

如果没装,去Node.js 官网下载安装,一路下一步就行,跟装 QQ 似的简单。

创建 React + TS 项目 🚀

最方便的方式是用官方脚手架 Create React App,一行命令搞定:

npx create-react-app my-ts-app --template typescript

这里的--template typescript就是告诉脚手架:"给我来个 TS 版本的!"

创建完成后,进入项目目录并启动:

cd my-ts-app
npm start

稍等片刻,浏览器会自动打开http://localhost:3000,你会看到一个带 TS 标志的 React 欢迎页面,说明环境搭建成功啦!🎉

项目目录小科普 📂

生成的项目里,有几个文件要特别注意:

  • .tsx后缀的文件:这是 TS 版的 JSX 文件,React 组件就写在这里
  • tsconfig.json:TS 的配置文件,里面可以设置类型检查的严格程度等
  • react-app-env.d.ts:声明文件,让 TS 认识 React 相关的类型

React + TypeScript 实战开发 👨‍💻

image.png

基础语法大揭秘 🔍

先从 TS 的基础类型学起,这些在 React 组件里都会用到:

// 基本类型
let count: number = 10; // 数字
const title: string = "Hello ts"; // 字符串
const isDone: boolean = true; // 布尔值

// 数组
const list: number[] = [1, 2, 3]; // 全是数字的数组
const strList: Array<string> = ["a", "b", "c"]; // 另一种写法

// 元组(固定长度和类型的数组)
const tuple: [number, string] = [1, "乡乡"]; // 第一个必须是数字,第二个必须是字符串

// 对象类型(用interface约束)
interface User {
  name: string;
  age: number;
  isSingle?: boolean; // 问号表示可选属性
}
const user: User = {
  name: "乡乡",
  age: 18,
  // isSingle可以不写,因为是可选的
};

是不是很简单?就像给变量加了个 "身份证",规定了它的类型。

React 组件开发 🏗️

函数组件与 Props 类型约束 📦

在 React 中,组件接收的参数叫 props,用 TS 约束 props 类型是最常见的操作。我们通常用interface来定义 props 的结构:

// NameEditComponent.tsx
import React from "react";

// 定义props的类型
interface Props {
  userName: string; // 必须传一个字符串类型的userName
  onChange: (e: React.ChangeEvent<HTMLInputElement>) => void; // 一个函数,接收输入事件
}

// 用React.FC<Props>来指定这是一个React组件,并且props要符合Props类型
const NameEditComponent: React.FC<Props> = ({ userName, onChange }) => {
  return (
    <>
      <label>Update name:</label>
      <input
        type="text"
        value={userName}
        onChange={onChange}
        placeholder="请输入姓名"
      />
    </>
  );
};

export default NameEditComponent;

这里的React.ChangeEvent<HTMLInputElement>是 React 内置的类型,表示输入框的 change 事件,里面包含了输入框的值等信息。有了这个约束,当你在组件里用e.target.value时,TS 会知道这是字符串类型,还会给你自动补全提示,简直不要太爽!

父组件如何传值 👨‍👦

上面定义的NameEditComponent需要父组件传userNameonChange,父组件可以这么写:

// App.tsx
import { useState } from "react";
import NameEditComponent from "./components/NameEditComponent";

function App() {
  // 用useState定义状态,指定类型为string
  const [name, setName] = useState<string>("initialName");

  // 定义事件处理函数,指定参数类型为React.ChangeEvent<HTMLInputElement>
  const setUsernameState = (event: React.ChangeEvent<HTMLInputElement>) => {
    setName(event.target.value); // 这里event.target.value会被TS识别为string
  };

  return (
    <>
      {/* 传值给子组件,TS会检查类型是否匹配 */}
      <NameEditComponent userName={name} onChange={setUsernameState} />
    </>
  );
}

export default App;

注意useState<string>("initialName")这里,我们指定了状态的类型是 string。其实 TS 很聪明,如果你不传类型,它会根据初始值自动推断,但显式指定类型能让代码更清晰,尤其是初始值为nullundefined的时候。

枚举类型小技巧 🎭

有时候我们需要一些固定的状态值,比如 "待处理"、"已完成"、"已拒绝",这时候可以用 TS 的枚举(但更推荐用as const的对象,性能更好):

// 推荐写法:用as const让对象的值变成只读的字面量类型
const Status = {
  Pending: 0,
  Fulfilled: 1,
  Rejected: 2
} as const;

// 这样pStatus的类型就是0,而不是number
const pStatus = Status.Pending;

这样当你写if (pStatus === Status.Pending)时,TS 会帮你检查是否拼写错误,比纯 JS 安全多了。

常见问题与解决方案 🧐

image.png

  1. "JSX 元素类型没有任何构造签名" 报错
    通常是因为忘了导入 React,或者组件类型定义错了。解决:确保组件用React.FC定义,或者在文件顶部加import React from 'react'
  2. 事件处理函数里拿不到e.target.value
    因为没指定事件类型。解决:给参数加上e: React.ChangeEvent<HTMLInputElement>之类的类型。
  3. 可选属性报错 "属性不存在"
    当你访问user.isSingle时,因为它是可选属性,TS 会提示可能不存在。解决:用user.isSingle?.toString()(可选链操作符),或者先判断if (user.isSingle)
  4. 组件传参时类型不匹配
    比如子组件要number,你传了string。解决:检查传参的类型,或者用Number()String()等方法转换类型。

总结与展望 🏁

image.png

恭喜你!看到这里,你已经掌握了 React + TypeScript 的入门知识 🎉 总结一下:

  • TypeScript 是 JS 的超集,核心是类型约束,能在编译时发现错误

  • React 组件用 TS 约束后,props 和 state 的类型更清晰,减少 Bug

  • interface用来定义对象类型,React.FC<Props>用来定义组件

  • 事件类型如React.ChangeEvent能让事件处理更安全

接下来你可以尝试:

  • 用 TS 写一个 TodoList(经典练手项目)

  • 学习 React Router 的 TS 用法

  • 探索状态管理库(如 Redux Toolkit)与 TS 的结合

记住,TypeScript 虽然一开始会让你多写一些代码,但从长远来看,它能帮你节省大量调试时间,尤其在团队协作和大型项目中,优势简直不要太明显。

最后送大家一句名言: "早用 TS 早轻松,晚用 TS 哭着冲"  😂 祝大家在 React + TypeScript 的世界里玩得开心,写出更健壮的代码!