你有没有经历过:凌晨三点,线上报"Cannot read property 'name' of undefined",你爬起来一看,原来是后端返回的数据少了一层。如果JS有"类型检查",这种悲剧根本不会发生。今天我们就来认识TypeScript------给JavaScript买了一份"意外险"。
前言
JavaScript就像个自由散漫的天才:你给它一个字符串,它当数字用;你忘记传参数,它给你个undefined;你访问对象不存在的属性,它笑眯眯地说"没事,我给你undefined"。这种灵活在小型项目里很爽,但项目一大,就成了噩梦。
TypeScript(简称TS)就是来解决这个问题的。它给JS加上了类型系统,在代码运行之前就帮你检查类型错误。就像给代码装了安检门,不规范的写法根本过不去。
一、TypeScript是啥?JS的"严格模式"Pro Max
TypeScript是微软开发的开源语言,它是JavaScript的超集。意思是:所有合法的JS代码,在TS里也合法。TS只是给JS加了类型注解和一些新特性,然后编译成干净的JS。
ts
// JS写法
function greet(name) {
return 'Hello, ' + name;
}
// TS写法(加了类型)
function greet(name: string): string {
return 'Hello, ' + name;
}
greet(123); // ❌ 报错:参数不能是数字
你看,TS在编译阶段就抓住了错误,不用等到运行时。
二、为什么要用TS?三个字:稳、爽、香
- 稳:类型错误在写代码时就暴露,而不是在用户手里炸。
- 爽:编辑器智能提示飞起,不用记方法名、参数顺序。
- 香:代码即文档,看函数签名就知道怎么用。
据统计,使用TS的项目,早期Bug能减少15%~25%。对于中大型项目,TS几乎是标配。
三、基础类型:TS的"基本词汇"
TS支持JS的所有类型,还加了一些新的。
1. 原始类型
ts
let name: string = '张三';
let age: number = 18;
let isStudent: boolean = true;
let nothing: null = null;
let notDefined: undefined = undefined;
let big: bigint = 100n;
let sym: symbol = Symbol('id');
2. 数组
ts
let list1: number[] = [1, 2, 3];
let list2: Array<string> = ['a', 'b']; // 泛型写法
3. 元组(固定长度和类型的数组)
ts
let person: [string, number] = ['张三', 18];
person[0] = '李四'; // OK
person[1] = '20'; // ❌ 报错,第二个元素必须是数字
4. 枚举(给一组数字起名字)
ts
enum Color { Red, Green, Blue }
let c: Color = Color.Red;
console.log(c); // 0(默认从0开始)
// 自定义值
enum Status { Success = 200, NotFound = 404 }
5. Any(万能类型,慎用)
ts
let notSure: any = 4;
notSure = '字符串'; // OK
notSure = true; // OK
any会关闭类型检查,相当于回到JS。尽量少用,除非你确定这个值无法预知类型。
6. Unknown(安全的Any)
ts
let value: unknown = 'hello';
value = 123; // OK
// console.log(value.toUpperCase()); // ❌ 报错,unknown不能直接调用方法
if (typeof value === 'string') {
console.log(value.toUpperCase()); // 类型收窄后可用
}
unknown比any安全,因为使用前必须先判断类型。
7. Void(没有返回值)
ts
function warnUser(): void {
console.log('警告');
}
// 变量声明为void类型只能赋值为null或undefined(strict模式下只能undefined)
8. Never(永远不会发生的类型)
ts
function error(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
四、类型注解:给变量贴标签
TS的核心就是类型注解 :在变量、函数参数、返回值后面加上: 类型。
ts
let myName: string = '张三';
function add(a: number, b: number): number {
return a + b;
}
但TS很智能,很多时候可以类型推断,不用显式写:
ts
let age = 18; // TS自动推断为number
age = '18'; // ❌ 报错
五、接口(Interface):定义对象的形状
接口是TS里最常用的功能,用来描述对象的结构。
ts
interface Person {
name: string;
age: number;
email?: string; // 可选属性
readonly id: number; // 只读属性
}
const zhangsan: Person = {
name: '张三',
age: 18,
id: 1
};
zhangsan.id = 2; // ❌ 报错,只读属性不能改
接口还可以描述函数类型:
ts
interface AddFunc {
(a: number, b: number): number;
}
const add: AddFunc = (x, y) => x + y;
六、类型别名(Type):给类型起外号
类型别名和接口很像,但能表示联合类型、元组等更复杂的类型。
ts
type ID = string | number; // 联合类型
type Point = [number, number]; // 元组
type Callback = (data: string) => void;
let userId: ID = 123;
userId = 'abc';
接口 vs 类型别名:
- 接口可以扩展(
extends),类型别名用交叉(&)。 - 接口可以重复定义自动合并,类型别名不能重复。
- 推荐优先用接口描述对象,用类型别名描述联合、元组等。
七、实战:用TS写一个简单的函数
ts
// 需求:格式化用户信息
interface User {
name: string;
age: number;
address?: string;
}
function formatUser(user: User, withAddress: boolean = false): string {
let base = `${user.name}, ${user.age}岁`;
if (withAddress && user.address) {
base += `, 地址:${user.address}`;
}
return base;
}
const u: User = { name: '李四', age: 20, address: '北京' };
console.log(formatUser(u, true)); // "李四, 20岁, 地址:北京"
如果你在编辑器里打formatUser(,它会提示参数类型和返回值类型,爽不爽?
八、常见坑点与建议
- 不要滥用any :any越多,TS的价值越低。实在不知道类型,先写
unknown。 - 严格模式 :开启
strict: true(tsconfig.json),让TS更严格地检查。 - 第三方库 :大多数库都有
@types/xxx类型定义,安装后就能获得智能提示。 - 编译后的JS:TS只负责编译时检查,运行时还是JS,类型信息会被擦除。
九、总结:TS不是敌人,是保镖
- 给JS加上类型,提前发现错误。
- 基础类型、接口、类型别名是核心工具。
- 用好类型推断,少写冗余注解。
- 逐步迁移老项目,从
.js改成.ts,开启allowJs: true。
学TS并不难,你只需要把"写JS时的心理预期"明确写出来。明天我们继续深入TypeScript,聊聊高级类型------泛型、联合类型、交叉类型、类型保护,让你写出更灵活更安全的代码。
如果你觉得今天的"保险课"够实在,点个赞让更多人看到。我们明天见!