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