TS-java转大前端的福音(终于遇见你)

4 阅读4分钟

前言

在代码的世界里,有一句话曾被无数开发者奉为圭臬:

“强类型可以杜绝 98% 的类型错误。”

TypeScript(下文简称 TS)的理解还停留在“会报错的 JavaScript”阶段。甚至有人在笔记里写道:“TS 是 JS 的超级”。

其实,准确的说法是:TS 是 JS 的“超集”(Superset)。

这意味着 TS 包含了 JS 的所有特性,并在此基础上像钢铁侠穿上战甲一样,增加了静态类型系统。TS 最终会被编译成 JS 在浏览器运行,但它能让你在代码运行前(编写阶段)就发现那些可能导致崩溃的 Bug。


一、 基础类型:告别“裸奔”的变量

在 JS 中,变量可以随意改变类型,这虽然灵活,但也是 Bug 的温床。TS 的第一步,就是给变量穿上“约束衣”。

TypeScript

// 基础类型注解
let b: string = 'hello';
let c: boolean = true;
let d: null = null;
let e: undefined = undefined;

// 数组的两种定义方式
let arr: number[] = [1, 2, 3, 4, 5]; // 方式一:类型[]
let arr2: Array<string> = ['a', 'b', 'c']; // 方式二:泛型 Array<T>

// 元组 (Tuple):一种特殊的数组,限定了长度和每个位置的类型
// let user = [1, 'Tom']; // 这样写 TS 会推导为 (string|number)[]
let user: [number, string] = [1, 'Tom']; // 这是元组,主要用于 CSV 解析或 React Hooks 返回值

提示:在实际开发中,如果变量有初始值,TS 会自动进行类型推导(Type Inference)。例如 let a = 18,TS 自动知道它是 number。不要给每个变量都写类型注解,那样代码会很啰嗦。


二、 枚举(Enum):拒绝“魔术数字”

在业务开发中,我们经常遇到状态判断,比如订单状态 0、1、2。如果直接写数字,代码很难维护(谁记得 2 代表什么?)。

TS 借鉴了 Java/C# 等语言,引入了 枚举。 TypeScript

enum Status {
    Pending, // 默认为 0
    Success, // 1
    Failed,  // 2
}

let s: Status = Status.Pending;

if (s === Status.Success) {
    // 逻辑清晰,可读性极高
}

划重点:枚举不仅增强了可读性,还是 TS 中少数会产生运行时代码的特性之一(稍后部分细说)。


三、 Any vs Unknown:放纵与克制的艺术

这是很多新手的重灾区,也是面试必考点。

1. Any:放弃治疗的救命稻草

TypeScript

// ts初学的时候 any救命
let aa: any = 1; // 任意类型,放弃类型约束
aa = "11"; 
aa = {};
aa = true; 
// 甚至可以调用不存在的方法,编译时不报错,运行时崩溃
// aa.fly();

当你把类型设为 any,你就把 TS 降级回了 JS。虽然写起来爽,但可能会导致严重的生产事故。大厂项目中,通常会在 ESLint 中禁用显式的 any。

2. Unknown:安全的防火墙

TS 3.0 引入了 unknown,它是 any 的安全版。

TypeScript

let bb: unknown = 1; // 未知类型
bb = 'b'; // 可以赋值任何类型

// bb.hello(); // 报错!对象是未知类型,不能随意调用方法

为什么 unknown 更安全?
因为它强制你在使用变量之前,必须进行类型检查(Type Narrowing)。

TypeScript

if (typeof bb === 'string') {
    console.log(bb.toUpperCase()); // TS 知道现在它是 string 了
}

四、 接口 (Interface) vs 类型别名 (Type)

这是定义对象结构的两种主要方式。

TypeScript

// --- Interface 方式 ---
interface User {
    name: string;
    age: number;
    readonly id: number; // 只读属性,初始化后不可修改
    hobby?: string;      // 可选属性,可传可不传
}

const u: User = {
    name: 'Tom',
    age: 18,
    id: 1001,
    hobby: 'reading',
}
// u.id = 1002; // 报错:id 是只读的

// --- Type Alias 方式 ---
type ID = string | number; // 联合类型,这是 Type 的强项

type UserType = {
    name: string;
    age: number;
    id: ID, // 复用上面定义的联合类型
    hobby?: string
}

很多同学会问:它俩到底用哪个?

特性InterfaceType
定义对象/函数支持支持
声明合并 (同名合并)支持 (适合库开发者)不支持 (报错)
联合类型/元组不支持支持 (type A = stringnumber)
扩展方式extends& (交叉类型)

大厂最佳实践

  • 编写库(Library)或插件时,优先用 interface,因为方便使用者扩展。
  • 定义联合类型、复杂的工具类型转换时,必须用 type。
  • 普通业务代码中,保持团队风格统一即可(目前 React 社区偏向用 type 略多一点)。

结语

回到文章开头的那段代码,看到 // ts初学的时候 any救命

从 JavaScript 的“随心所欲”到 TypeScript 的“循规蹈矩”,初学者一定会感到痛苦和束缚。但请相信我,当你维护一个超过 5 万行代码的大型项目时,那些红色的波浪线报错,不再是阻碍你的绊脚石,而是防止你跌入深渊的护栏。

TS 不仅是技术,更是一种严谨的工程思维。