第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 看不到未来传什么 → 必须手动标
- 变量赋值 → 看得到值 → 让 TS 推断
- 函数参数 → 定义时没有值 → 必须手动标
- 判断法:那一刻 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} />;
}
- 命名约定:组件名 + Props(
PhotoCard→PhotoCardProps)。 - 用错当场拦:
<PhotoCard author="K" />→ 报错少了 url。
⚠️ 为什么标在花括号后面,不是小括号后面?
function PhotoCard({ author, url }: PhotoCardProps) { }
// 小括号后面那个位置 = 留给"返回值类型"的
标在小括号后面会变成”组件返回 PhotoCardProps”,错了(组件返回 JSX)。
- 花括号后面 = 参数(props 对象)的类型 ✅
- 小括号后面 = 返回值类型(组件让 TS 推断 JSX,通常不写)
函数类型的 prop(回调)
interface SearchBarProps {
query: string;
onQueryChange: (value: string) => void;
// ↑ 函数类型:接收 string 参数,不返回值(void)
}
(value: string) => void—— 接收一个 string,无返回值。void= 无返回值(回忆 setQuery/onQueryChange 返回 undefined,只为触发动作)。- 无参数的函数:
() => 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
string | null= “要么是字符串,要么是 null”。- 匹配真实逻辑:copied 初始 null,复制时变字符串,之后变回 null。
判断法
- 初始值能代表 state 将来的类型(数字/字符串/布尔)→ 让 TS 推断
- 初始值是 null/空,将来会变成别的类型 → 用
<Type | null>手动标
// 例:选中的用户对象,或没选
const [selectedUser, setSelectedUser] = useState<User | null>(null);
第9周验收
- 懂 TS 解决什么(编译期类型检查,提前抓 bug)
- 会基础类型标注 + 知道基础类型是小写
- 懂类型推断:看得到值就推断,函数参数必须手动标
- 会用 interface 描述对象形状
- 会给 React props 标类型(props 是对象,interface 标在解构花括号后)
- 会写函数类型 prop
(v: string) => void - 懂 useState 类型:多数推断,null 初始值用
<Type | null>