一、类型系统全景图
TypeScript 在 JavaScript 类型基础上进行了扩展和强化:
-
JavaScript 基础类型继承:
number
,string
,boolean
,null
,undefined
,symbol
,bigint
object
(包含子类型:Array
,Function
,Date
,RegExp
等)
-
TypeScript 新增核心类型:
void
: 表示"没有返回值"(函数无返回或返回undefined
)。never
: 表示"永不存在的值"(函数抛出异常或死循环)。unknown
: 表示"未知类型"(类型安全的any
,需先断言或检查)。any
: 表示"任意类型"(放弃类型检查,慎用!)。enum
: 枚举类型(定义具名常量集合)。tuple
: 元组类型(固定长度和类型的数组)。
-
自定义类型工具:
type
: 类型别名(定义复杂类型或联合/交叉类型)。interface
: 接口(主要描述对象/类的形状,支持声明合并)。
注意: JavaScript 的包装对象构造函数 (
Number
,String
,Boolean
) 在 TS 中同样极少直接使用,主要用于处理原始值包装对象。
二、核心类型详解与最佳实践
-
any
vsunknown
: 灵活性与安全的抉择any
: 终极逃生舱。赋予变量后,TS 放弃所有类型检查。尽量避免,它削弱了 TS 的核心优势。unknown
: 类型安全的any
。表示值类型未知。必须 在使用前进行类型检查(typeof
,instanceof
)或类型断言(as
)。适用于动态内容(如解析用户输入、第三方库返回值)的初始接收。
inilet userInput: unknown = fetchExternalData(); // 初始未知 if (typeof userInput === 'string') { console.log(userInput.toUpperCase()); // 安全使用 }
-
never
: 表示不可能发生的终点-
用于永远不会正常返回的函数:
- 抛出异常:
function fail(message: string): never { throw new Error(message); }
- 无限循环:
function infiniteLoop(): never { while(true) { ... } }
- 抛出异常:
-
在条件类型中表示不可能的分支。
-
与
void
区别:void
表示无返回值(隐含undefined
),never
表示函数根本无法完成执行。
-
-
void
: 空或无显式返回- 主要用于函数返回值类型,表示函数不返回任何有效值(或只返回
undefined
)。 - 严格模式下 (
strictNullChecks
) 不能将null
赋给void
类型变量。
luafunction logMessage(msg: string): void { console.log(msg); // 无 return 语句,或 `return;` / `return undefined;` }
- 主要用于函数返回值类型,表示函数不返回任何有效值(或只返回
-
object
vsObject
: 对象的微妙差异object
: 指非原始值 类型 (string
,number
,boolean
,symbol
,bigint
,null
,undefined
之外的类型)。包括对象、数组、函数等。范围较宽,使用较少。Object
(大写 O): 指 JavaScript 的全局Object
类型或其派生实例。范围极大(几乎包含除null
和undefined
外的所有值),几乎不用 。{}
常被用来表示"任意非null
/undefined
的对象"。
-
tuple
: 定长定类型的数组- 精确描述数组中特定位置元素的类型。
inilet point: [number, number] = [10, 20]; // 正确 point = [10]; // 错误: 长度不匹配 point = [10, '20']; // 错误: 第二个元素类型不匹配
-
type
&interface
: 自定义类型的利器type
: 创建类型别名。适用于定义联合类型、交叉类型、元组、函数类型、映射类型等。
typescripttype ID = string | number; type Point = { x: number; y: number }; type Callback = (data: string) => void;
interface
: 主要用于定义对象 的形状,描述其应有的属性和方法。支持extends
继承和implements
实现。关键特性是声明合并(同名接口自动合并)。
typescriptinterface Person { name: string; age: number; greet(): void; } interface Person { // 声明合并 email?: string; // 可选属性 }
-
抽象类 (
abstract class
): 蓝图的蓝图- 不能直接实例化 (
new AbstractClass()
会报错)。 - 可以包含具体方法的实现。
- 可以包含
abstract
方法(只有声明,没有实现)。派生类必须实现所有抽象方法。 - 用于定义公共结构和强制契约。
scalaabstract class Animal { abstract makeSound(): void; // 抽象方法,子类必须实现 move(): void { // 具体方法 console.log('Moving...'); } } class Dog extends Animal { makeSound() { // 实现抽象方法 console.log('Woof!'); } }
三、精确控制:属性修饰符
- 不能直接实例化 (
修饰符用于控制类成员(属性/方法)的可见性和可变性:
-
readonly
: 只读堡垒- 标记属性只能在声明时或构造函数中初始化一次,之后不可修改。
- 提供初始化后的不变性保证。
iniclass Circle { readonly PI: number = 3.14159; readonly radius: number; constructor(r: number) { this.radius = r; } // this.radius = 10; // 错误!不能在方法中修改 readonly }
-
访问控制三剑客 (
public
,protected
,private
):public
(默认): 公开成员。任何地方(类内部、子类内部、类实例)都可访问。protected
: 受保护成员。只能在类内部 及其子类内部 访问。类实例无法访问。private
: 私有成员。仅在声明它的类内部访问。子类和类实例都不可访问。
scalaclass Base { public publicProp = 1; protected protectedProp = 2; private privateProp = 3; } class Derived extends Base { access() { console.log(this.publicProp); // OK console.log(this.protectedProp); // OK (在子类内部) // console.log(this.privateProp); // 错误!私有成员 } } const base = new Base(); console.log(base.publicProp); // OK // console.log(base.protectedProp); // 错误!受保护成员 // console.log(base.privateProp); // 错误!私有成员
四、泛型 (
Generics
): 类型参数化
用于在定义函数、类或接口 时,暂不指定具体类型,而在使用时再明确类型。提升代码复用性和类型安全性。
-
基本语法 (
<T>
):csharpfunction identity<T>(arg: T): T { return arg; } let output1 = identity<string>("hello"); // 显式指定 T 为 string let output2 = identity(42); // 类型推断 T 为 number
-
多泛型参数:
inifunction swap<U, V>(tuple: [U, V]): [V, U] { return [tuple[1], tuple[0]]; } let result = swap([10, "twenty"]); // result 类型为 [string, number]
-
泛型约束 (
extends
): 限制泛型参数必须满足某些条件。matlabinterface Lengthwise { length: number; } function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); // 确保 arg 有 .length 属性 return arg; } loggingIdentity([1, 2, 3]); // OK, 数组有 length loggingIdentity({ length: 10, value: 3 }); // OK, 对象有 length // loggingIdentity(3); // 错误!数字没有 .length
-
泛型类:
kotlinclass Box<T> { private content: T; constructor(value: T) { this.content = value; } getValue(): T { return this.content; } } const stringBox = new Box("TypeScript"); const numberBox = new Box(100);
总结: TypeScript 的类型系统是其灵魂所在。从基础类型的精确描述到
any
/unknown
/never
等特殊类型的场景化应用,再到type
/interface
提供的强大自定义能力,以及属性修饰符对封装性的控制和泛型带来的高度复用性,共同构成了构建可维护、可预测且健壮的大型应用程序的坚实基石。深刻理解并合理运用这些概念,是提升 TypeScript 开发水平的关键。