Day 08 - TypeScript 基础类型
·
Day 08 - TypeScript 基础类型
今天学完你能做什么
- 理解 TypeScript 和 JavaScript 的关系
- 给变量、函数参数和返回值加上类型
- 看懂各种类型标注,不再害怕红色波浪线
一、TypeScript 是什么?——给 JavaScript 装上"安检门"
// JavaScript —— 自由但容易出错
function add(a, b) {
return a + b;
}
add(1, "2"); // "12" —— 字符串拼接?不是你要的!
add(1, null); // 1 —— 不报错但奇怪
add("hello", {});// "hello[object Object]" —— 什么鬼?
// TypeScript —— 加上类型约束
function add(a: number, b: number): number {
return a + b;
}
add(1, 2); // ✅ 3
// add(1, "2"); // ❌ 编译就报错!在你运行之前就发现了 bug
TypeScript = JavaScript + 类型系统。 它就是给 JS 装了"安检门"——不合规的数据根本进不来。
二、基础类型速览
2.1 原始类型
let name: string = "张三"; // 字符串
let age: number = 25; // 数字(不分 int/float)
let isStudent: boolean = true; // 布尔值
let nothing: null = null; // 空值
let notDefined: undefined = undefined; // 未定义
let bigNumber: bigint = 100n; // 大整数
let unique: symbol = Symbol("id"); // 唯一标识符
2.2 数组
let fruits: string[] = ["苹果", "香蕉", "橙子"];
let scores: number[] = [88, 92, 76];
let flags: boolean[] = [true, false, true];
// 泛型写法(概念在下一节讲)
let names: Array<string> = ["A", "B", "C"];
// 混合类型数组(元组——见下文)
2.3 any —— 万能类型(尽量少用)
let anything: any = "hello";
anything = 123; // ✅ 可以
anything = true; // ✅ 可以
anything.foo.bar(); // ✅ 不报错(但运行时会炸!)
// any 等于关闭了 TypeScript 的类型检查
// 只在迫不得已时用(比如处理第三方库的数据)
2.4 unknown —— 安全的 any
let input: unknown = "用户输入";
input = 42;
input = { data: [] };
// ❌ 不能直接使用 unknown 类型的值
// input.toUpperCase(); // 报错!
// ✅ 必须先检查类型
if (typeof input === "string") {
console.log(input.toUpperCase()); // 安全!
}
| any | unknown |
|---|---|
| 关掉所有检查 | 保留检查,必须你自己判断 |
| 不安全 | 安全 |
| 少用 | 推荐替代 any |
2.5 void —— 没有返回值
// 函数不返回任何东西时用 void
function logMessage(msg: string): void {
console.log(msg);
// 没有 return 语句
}
function showError(msg: string): void {
console.error(msg);
return; // return 后面没有值
}
2.6 never —— 永远不会返回
// 抛出异常的函数,永远不会正常返回
function throwError(msg: string): never {
throw new Error(msg);
}
// 死循环函数
function infiniteLoop(): never {
while (true) {
// 永远不会结束
}
}
三、类型推断——你不写 TS 也能猜出来
let name = "张三"; // TS 推断为 string
let age = 25; // TS 推断为 number
let isOk = true; // TS 推断为 boolean
// name = 123; // ❌ 报错!TS 已经推断 name 是 string
// 数组推断
let nums = [1, 2, 3]; // number[]
let mixed = [1, "a"]; // (string | number)[]
建议: 如果 TS 能推断出来,就不用写类型。只在函数参数、复杂结构时显式标注。
四、联合类型——可能是 A 也可能是 B
// 一个变量可以是多种类型之一
let id: string | number;
id = "abc123"; // ✅
id = 456; // ✅
// id = true; // ❌
// 函数参数也常用
function printId(id: string | number) {
if (typeof id === "string") {
console.log(id.toUpperCase());
} else {
console.log(id.toFixed(2));
}
}
五、字面量类型——只能是这几个值
// 限定具体的值
let direction: "left" | "right" | "up" | "down";
direction = "left"; // ✅
// direction = "forward"; // ❌
let statusCode: 200 | 404 | 500;
statusCode = 200; // ✅
// statusCode = 300; // ❌
// 实际应用:限制函数参数
function setAlign(align: "left" | "center" | "right") {
console.log(`对齐方式: ${align}`);
}
setAlign("center"); // ✅
// setAlign("top"); // ❌
六、元组 Tuple——固定长度、固定类型的数组
// [string, number] 表示:第1个是 string,第2个是 number
let user: [string, number] = ["张三", 25];
// 访问
console.log(user[0].toUpperCase()); // ✅ string 方法
console.log(user[1].toFixed(2)); // ✅ number 方法
// 解构
const [userName, userAge] = user;
// 实际应用:API 返回的固定格式数据
let apiResponse: [number, string, any] = [200, "成功", { data: [] }];
七、枚举 Enum——给一组值起名字
// 数字枚举(默认从 0 开始)
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right // 3
}
let dir: Direction = Direction.Up;
// 自定义值
enum Status {
Success = 200,
NotFound = 404,
ServerError = 500
}
// 字符串枚举
enum Color {
Red = "#FF0000",
Green = "#00FF00",
Blue = "#0000FF"
}
八、类型别名——给类型起个外号
// 复杂类型写一次,后面复用
type UserId = string | number;
type Point = { x: number; y: number };
type Callback = (data: any) => void;
function getUser(id: UserId) { /* ... */ }
function drawPoint(p: Point) { /* ... */ }
九、可选链 ?. —— 安全地访问深层属性
9.1 没有可选链之前——层层判空,噩梦!
// 场景:获取用户的公司的地址的城市
const user = {
name: "张三",
company: {
name: "某科技公司",
address: {
city: "北京"
}
}
};
// ❌ 传统写法——每层都要判空,否则报错
let city;
if (user && user.company && user.company.address) {
city = user.company.address.city;
}
console.log(city); // "北京"
// 如果 company 不存在?
const user2 = { name: "李四" };
// user2.company.address.city → 💥 报错!
9.2 可选链一行搞定
// ✅ 可选链 ?. —— 前面为 null/undefined 时直接返回 undefined,不会报错
const city = user?.company?.address?.city;
console.log(city); // "北京"
const city2 = user2?.company?.address?.city;
console.log(city2); // undefined(不报错!)
类比: 可选链就像过独木桥——每一步先伸脚试探,踩空了就退回来,不会掉下去。
9.3 可选链的各种用法
// 对象属性
const name = obj?.name;
// 数组元素
const firstItem = arr?.[0];
// 函数调用(如果函数存在才调用)
const result = callback?.();
// 组合使用
const value = data?.items?.[0]?.toUpperCase?.();
// 与空值合并 ?? 搭配
const city = user?.company?.address?.city ?? "未知城市";
十、空值合并 ?? —— 只有 null/undefined 才用默认值
10.1 || 和 ?? 的天壤之别
// || 的坑:会把 0、""、false 都当成"假"
const count1 = 0 || 10; // 10 —— 0 被错误地替换了!
const name1 = "" || "匿名"; // "匿名" —— 空字符串被替换了!
const enabled1 = false || true; // true —— false 被替换了!
// ✅ ?? 只在 null 和 undefined 时才启用默认值
const count2 = 0 ?? 10; // 0 —— 0 是有效的数字!
const name2 = "" ?? "匿名"; // "" —— 空字符串也是有效值!
const enabled2 = false ?? true; // false 正确保留!
const count3 = null ?? 10; // 10 —— null 才替换
const count4 = undefined ?? 10; // 10 —— undefined 才替换
10.2 生活类比
|| 就像一个"过于热心的人":你没吃饭?我把饭给你。你只吃了一口?那也算没吃,饭拿走!
?? 就像一个"精准的人":你没吃饭(null/undefined)?给你。你吃了但没吃饱(0/"")?那是你自己的事。
10.3 实战搭配
// 可选链拿到值,空值合并给默认值——黄金搭档
function getDisplayName(user: { name?: string; nickname?: string } | null) {
return user?.name ?? user?.nickname ?? "匿名用户";
}
console.log(getDisplayName(null)); // "匿名用户"
console.log(getDisplayName({ name: "张三" })); // "张三"
console.log(getDisplayName({ nickname: "小明" })); // "小明"
console.log(getDisplayName({ name: "", nickname: "小明" })); // ""(空字符串是有效值!)
十一、Set 与 Map —— ES6 新增数据结构
11.1 Set —— 不重复的集合
// 就像一盒巧克力,每种口味只能放一颗
// 创建
const flavors = new Set<string>();
// 添加
flavors.add("草莓");
flavors.add("抹茶");
flavors.add("草莓"); // 重复了,自动忽略
console.log(flavors); // Set { "草莓", "抹茶" } 只有 2 个!
// 最常用:数组去重——一行搞定!
const arr = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(arr)];
console.log(unique); // [1, 2, 3, 4]
// 其他操作
console.log(flavors.has("草莓")); // true
console.log(flavors.size); // 2
flavors.delete("草莓");
flavors.clear(); // 清空
11.2 Map —— 任意类型的键值对
// 普通对象 { } 的键只能是 string 或 symbol
// Map 的键可以是任意类型:对象、数字、函数...都可以!
const cache = new Map<object, string>();
const user1 = { id: 1 };
const user2 = { id: 2 };
cache.set(user1, "张三的数据");
cache.set(user2, "李四的数据");
console.log(cache.get(user1)); // "张三的数据"
console.log(cache.size); // 2
// 遍历
for (const [key, value] of cache) {
console.log(key, "→", value);
}
// 判断是否存在
console.log(cache.has(user1)); // true
cache.delete(user1);
// 常见场景:用对象做键的缓存
const requestCache = new Map<string, { data: any; time: number }>();
requestCache.set("/api/users", { data: ["张三"], time: Date.now() });
11.3 Set / Map vs 普通对象/数组
| 需求 | 用这个 | 为什么 |
|---|---|---|
| 数组去重 | new Set(arr) |
天然不重复 |
| 检查元素是否存在 | Set.has() |
O(1) 比 arr.includes() 的 O(n) 快 |
| 大量键值对增删 | Map |
比对象快,键可以是任意类型 |
| 固定结构的配置 | 普通对象 {} |
简单直观 |
今日小结
┌───────────────────────────────────────────┐
│ │
│ TypeScript = JavaScript + 类型 │
│ │
│ 基础类型:string, number, boolean │
│ 特殊类型:null, undefined, void, never │
│ 万能类型:any(少用), unknown(安全) │
│ 组合类型:联合 |, 字面量, 元组 [T, U] │
│ │
│ 可选链 ?. → 安全访问,遇空返回 undefined │
│ 空值合并 ?? → 只在 null/undefined 用默认 │
│ Set → 去重集合,一行搞定 │
│ Map → 任意类型做键的键值对 │
│ │
│ 类型推断:不写 TS 也能猜出来 │
│ 类型别名:type 关键字给类型起名字 │
│ │
│ 口诀:冒号后面写类型,编译就检查,运行前防错 │
│ │
└───────────────────────────────────────────┘
更多推荐




所有评论(0)