第9周笔记-TypeScript 入门(给 React 加类型)

路线图阶段:第二阶段(TypeScript)第9周 目标:能舒服地读写带类型的 React,不求精通 —— 不碰高级类型体操 核心:给你已经会写的 React 代码,加上类型


0. TypeScript 解决什么问题

JavaScript 不检查类型,TypeScript 检查。

function double(n) { return n * 2; }
double("5");   // JS: "55"(诡异),不报错,运行时才暴露
function double(n: number) { return n * 2; }
double("5");   // TS: 编辑器当场标红,string 不能传给 number

⚠️ 刚上手 TS 会报一堆 JS 时代不用管的错 —— 这不是你写错,是 TS 在帮你提前抓 bug。适应几天就好。

类比设计

类型就像 Figma 组件的”属性约束”:布尔属性填不进文字,工具会拦你。 TS 给代码加同样的约束:用错类型,编辑器当场拦截,而非线上才出 bug。


1. 基础类型标注:变量名: 类型

let name: string = "Kevin";       // 字符串
let age: number = 31;             // 数字(整数小数都是 number)
let isActive: boolean = true;     // 布尔
let tags: string[] = ["a", "b"];  // 字符串数组(类型后加 [])

⚠️ 基础类型全是小写:string / number / boolean。 看到大写开头的(String / StringIterator / Number)基本不是日常要用的 —— 别被编辑器自动补全带偏,选补全前看一眼。


2. 类型推断(Type Inference):能推断的地方不用标

let city = "Osaka";   // TS 自动推断 city 是 string
let count = 0;        // TS 自动推断 count 是 number

TS 看得到等号右边的值,就能自己推断,不用手动标。

什么时候必须手动标? —— TS”看不到值”的时候

function greet(name: string, age: number) { ... }
//             ↑ 参数在定义时还没有值(将来调用才传进来)
//               TS 看不到未来传什么 → 必须手动标

返回值类型也能推断

function greet(name: string, age: number): string { ... }
//                                        ↑ 返回值类型,但通常可省略
// TS 能从 return 的内容自己推断,不写也知道

3. interface:描述”对象的形状”

interface User {
  name: string;
  age: number;
}

const kevin: User = { name: "Kevin", age: 31 };
// kevin 必须符合 User 形状:有 name(string)和 age(number)

漏字段、类型不对 → TS 当场报错。

类比设计

interface 就是组件的”属性清单”:规定一个对象必须长什么样(哪些属性、各是什么类型)。


4. 给 React props 加类型(本周正题)

关键认知:props 本身就是一个对象

React 传给组件的是一个对象,组件函数其实只有一个参数:

// 不解构:类型标在参数 props 后面
function PhotoCard(props: PhotoCardProps) { }

// 解构:{ author, url } 就是"那一个 props 参数",被拆开了
//      类型标在整个 {} 后面
function PhotoCard({ author, url }: PhotoCardProps) { }
//                 └─参数(解构)─┘ └─它的类型─┘

所以给 props 标类型 = 给一个对象标 interface,和 const kevin: User 是同一件事。

完整写法

interface PhotoCardProps {
  author: string;
  url: string;
}

function PhotoCard({ author, url }: PhotoCardProps) {
  return <img src={url} alt={author} />;
}

⚠️ 为什么标在花括号后面,不是小括号后面?

function PhotoCard({ author, url }: PhotoCardProps) { }
//                 小括号后面那个位置 = 留给"返回值类型"的

标在小括号后面会变成”组件返回 PhotoCardProps”,错了(组件返回 JSX)。

函数类型的 prop(回调)

interface SearchBarProps {
  query: string;
  onQueryChange: (value: string) => void;
  //              ↑ 函数类型:接收 string 参数,不返回值(void)
}

5. useState 的类型

多数情况:自动推断,不用标

const [primaryHex, setPrimaryHex] = useState("#C16952"); // 推断 string ✅
const [count, setCount] = useState(0);                   // 推断 number ✅

初始值能代表类型 → 让 TS 推断。这就是很多 useState 在 TS 里和 JS 看起来一样的原因。

需要手动标:初始值是 null 但将来会变别的类型

const [copied, setCopied] = useState(null);
setCopied("primary");   // ❌ TS 推断 copied 只能是 null,塞 string 报错

// 解法:用泛型 <> 标完整类型
const [copied, setCopied] = useState<string | null>(null);  // ✅

联合类型(union type):A | B

useState<string | null>(null)
//        ↑ 竖线 | 读作"或":这个值可以是 string,也可以是 null

判断法

// 例:选中的用户对象,或没选
const [selectedUser, setSelectedUser] = useState<User | null>(null);

第9周验收