本篇文章几乎全部由大语言模型(QWen3:8b)生成,本文主要目的是为了形成一个关于TS的快速查阅资料,对本人来说,装饰器那段有点过于拗口,各位看官请酌情观看.
一、TypeScript概述
JavaScript 作为一门动态类型语言,在开发大型应用时容易出现以下问题:
- 类型错误难以发现:运行时错误可能导致调试成本高。
- 代码可维护性差:缺乏类型定义,团队协作时容易理解代码逻辑。
- 缺乏工具支持:IDE 无法提供精准的代码提示和重构支持。
TypeScript 的诞生正是为了解决这些问题,它是由微软开发的一种开源编程语言,它是 JavaScript 的超集,在 JavaScript 的基础上添加了 静态类型、类型推断、接口、泛型 等高级特性。它由 Dmitry A. Soshnikov 和 Anders Hejlsberg(C# 和 Visual Studio 的架构师)共同设计,旨在解决 JavaScript 在大型项目中常见的维护性、可读性和错误排查困难等问题。TypeScript 的核心价值在于 "类型安全" 和 "开发体验优化"。它通过静态类型检查减少运行时错误,结合现代 JavaScript 特性(如 ES6+),使开发者能够构建更可靠、可维护的代码。随着前端和后端开发的复杂化,TypeScript 已成为现代 Web 开发的主流选择之一。
1. 核心特性
- 静态类型系统:开发者可以为变量、函数参数、返回值等定义明确的类型,编译器会在编译时检查类型是否匹配。
- 类型推断:即使不显式声明类型,TypeScript 也能通过上下文推断出变量类型(例如 let x = 10; 会被推断为 number)。
- 接口(Interfaces):定义对象的结构,用于类型检查和抽象设计。
- 泛型(Generics):编写可复用的组件,支持多种数据类型。
- 装饰器(Decorators):用于增强类、方法、参数等的元编程能力(如添加日志、验证等)。
- 模块系统:支持模块化开发,便于代码组织和复用。
2. 编译与运行
TypeScript 代码需要通过 TypeScript 编译器(tsc) 转换为 JavaScript,因为浏览器和 Node.js 仅支持 JavaScript。编译过程会检查类型错误,并生成兼容的 JavaScript 代码(如 ES5、ES6 等)。最终的 JavaScript 代码可以在任何支持 JS 的环境中运行。
3. 应用场景
- 大型前端项目:如 React、Vue、Angular 等框架广泛支持 TypeScript,帮助开发者构建可维护的复杂应用。
- 后端开发:Node.js 项目中使用 TypeScript 可提升代码的可读性和健壮性。
- API 接口定义:通过接口明确数据结构,确保前后端交互的准确性。
- 工具库开发:泛型和类型系统使工具库更灵活、可扩展。
4. 生态与工具
IDE 支持:VS Code、WebStorm 等编辑器提供智能提示、代码补全、类型检查等功能。
TypeScript Playground:在线编辑器,可实时测试 TypeScript 代码。
社区与资源:丰富的文档、教程、开源项目和社区支持,帮助开发者快速上手。
二、基础类型系统
1. 基本类型
TS语言支持一下数据类型。
| 类型 | 描述 | 示例 |
|---|---|---|
boolean |
表示布尔值,取值为 true 或 false |
let isDone: boolean = false; |
number |
表示数字(包括整数和浮点数) | let decimal: number = 6.4; |
string |
表示字符串(Unicode字符序列) | let name: string = "Alice"; |
null |
表示空值,通常用于表示变量未赋值 | let empty: null = null; |
undefined |
表示变量未赋值 | let value: undefined; |
symbol |
表示唯一标识符(常用于对象属性键) | let key: symbol = Symbol("key"); |
void |
表示函数没有返回值 | function log(message: string): void { console.log(message); } |
any |
表示任意类型(类型检查被绕过) | let x: any = "hello"; |
array |
表示数组类型(使用方括号表示) | let list: number[] = [1, 2, 3]; |
tuple |
表示固定长度的元组类型(指定元素类型和顺序) | let point: [number, string] = [42, "hello"] |
enum |
表示枚举类型(命名的常量集合) | enum Color { Red, Green, Blue } |
2. 类型推断
TS支持静态类型推断
typescript
let score = 95; // TypeScript 会自动推断为 number 类型
3.空值类型
typescript
function warn(message: string | null): void {
if (message) {
console.log(message);
} else {
console.log("No message");
}
}
4. 类型断言
指定某个变量的类型
typescript
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
三、泛型 (Generics)
泛型是一种参数化类型的机制,允许你编写与类型无关的代码,在使用时再指定具体的类型。它类似于数学中的"占位符",在编译时会根据实际传入的类型进行类型检查和优化。
typescript
// 普通函数(只能处理特定类型)
function printArray(arr: number[]) {
arr.forEach(item => console.log(item));
}
// 使用泛型的函数(可以处理任意类型)
function printArray<T>(arr: T[]) {
arr.forEach(item => console.log(item));
}
1. 泛型函数
typescript
function identity<T>(arg: T): T {
return arg;
}
2.泛型类
typescript
class Box<T> {
contents: T;
constructor(value: T) {
this.contents = value;
}
getContents(): T {
return this.contents;
}
}
3.泛型接口
typescript
interface Pair<T> {
first: T;
second: T;
}
4.泛型约束
泛型约束(Generic Constraints)是指通过限制泛型参数的类型范围,确保在使用泛型时,类型满足特定条件(如必须具有某些属性或方法)。通过约束,可以避免类型错误,并增强代码的类型安全性。
typescript
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // OK
return arg;
}
可以使用 & 操作符为泛型参数添加多个约束:
typescript
function example<T extends string & { id: number }>(arg: T): void {
console.log(arg.id); // 安全访问 id 属性
}
可以为泛型参数指定默认约束:
typescript
function example<T extends string = string>(arg: T): void {
console.log(arg.length); // string 有 length 属性
}
四、装饰器 (Decorators)
装饰器是 TypeScript 中的一种元编程特性,它允许开发者在不修改原始代码 的情况下,向类、方法、属性或参数添加额外的功能或修改。装饰器本质上是一个函数 ,它接收被装饰的类或成员作为参数,并返回一个修改后的类或成员。装饰器有以下几类
类装饰器(Class Decorator):
方法装饰器(Method Decorator):
属性装饰器(Property Decorator):
参数装饰器(Parameter Decorator):
1.类装饰器
类装饰器作用于类,可以修改类的结构,例如添加属性、方法等。
typescript
function Component<T>(target: Function): T | void {
target.isComponent = true;
return target;
}
@Component()
class MyComponent {
// ...
}
2. 方法装饰器
方法装饰器作用于类的方法,可以修改方法的行为。
typescript
function Log(target: any, key: string, descriptor: PropertyDescriptor): PropertyDescriptor {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${key} with`, args);
return originalMethod.apply(this, args);
};
return descriptor;
}
class MyClass {
@Log
greet(message: string) {
console.log(message);
}
}
3.属性装饰器
属性装饰器作用于类的属性,可以用来修改属性的类型、值等。
typescript
function MinValue(min: number) {
return (target: any, key: string) => {
let value = target[key];
if (value < min) {
throw new Error(`Value must be at least ${min}`);
}
};
}
class MyClass {
@MinValue(10)
value: number = 5;
}
4. 参数装饰器
参数装饰器作用于类的方法或属性的参数,可以用来修改参数的行为。
typescript
function Required(target: any, key: string, index: number) {
console.log(`Parameter ${index} of method ${key} is required`);
}
class MyClass {
greet(@Required message: string) {
console.log(message);
}
}
5.装饰器的执行顺序
当多个装饰器作用于同一个目标时,它们按照从上到下的顺序应用,但执行顺序是从下到上(先执行后写的装饰器)。
五、接口 (Interfaces)
1. 什么是接口?
在 TypeScript 中,接口(Interface) 是一种定义对象结构的类型。它描述了一个对象应该具有的属性、方法、索引签名 和 类型,但不提供具体的实现。接口主要用于类型检查,确保对象符合预定义的结构。接口是 TypeScript 中实现面向对象编程的重要概念,它帮助开发者明确类、对象、函数等的契约,提高代码的可读性和可维护性,它提供了以下优势:
** 类型安全:确保对象结构符合预期。**
** 代码清晰:明确表达代码的契约和意图。**
** 可维护性:通过接口隔离变化,提高代码的灵活性。**
** 文档作用:作为代码设计的文档,帮助理解接口的设计意图。**
** 在实际开发中,应合理使用接口,避免过度设计,同时注意与类型别名的区别,根据具体场景选择合适的方式。**
2.接口的基本用法
** 定义接口**
使用 interface 关键字定义接口:
typescript
interface User {
id: number;
name: string;
email?: string; // 可选属性
}
实现接口
类或对象可以通过显式实现或隐式实现接口:
typescript
class UserImpl implements User {
id: number;
name: string;
constructor(id: number, name: string) {
this.id = id;
this.name = name;
}
}
接口的类型检查
TypeScript 编译器会检查实现接口的对象是否满足接口定义的所有属性和方法:
typescript
const user: User = {
id: 1,
name: "Alice"
// email: "alice@example.com" // 可选属性,可以省略
};
// 编译器会报错,因为对象缺少 id 和 name 属性
const invalidUser: User = {
age: 25 // 错误:缺少 id 和 name
};
2.接口的高级特性
泛型与接口加粗样式
接口可以结合泛型,使定义更灵活:
typescript
interface KeyValuePair<K, V> {
key: K;
value: V;
}
const pair: KeyValuePair<number, string> = { key: 1, value: "hello" };
**可选属性与只读属性 **
可选属性:使用 ? 定义属性是否可选。
只读属性:使用 readonly 关键字定义属性不可修改。
typescript
interface Point {
readonly x: number; // 只读属性
y?: number; // 可选属性
}
索引签名
接口可以通过索引签名定义数组或其他映射类型的结构:
typescript
interface Dictionary {
[key: string]: number;
}
const dict: Dictionary = {
a: 1,
b: 2
};
类型约束
在接口中,可以使用泛型约束来限制属性类型:
typescript
interface Lengthwise<T extends { length: number }> {
length: number;
}
function getLength<T extends Lengthwise<T>>(obj: T): number {
return obj.length;
}
** 扩展接口 **
使用 extends 关键字扩展已有接口:
typescript
interface User {
id: number;
name: string;
}
interface UserWithEmail extends User {
email: string;
}
const user: UserWithEmail = {
id: 1,
name: "Alice",
email: "alice@example.com"
};
接口与类型别名
在 TypeScript 中,接口 和 类型别名(type) 很相似,但它们有一些区别:
定义结构:两者都可以定义对象结构。
合并:接口可以被多次扩展(extends),而类型别名不能。
重写:接口不能重写,而类型别名可以重写。
静态成员:接口不能定义静态成员,而类型别名可以。
示例:
typescript
// 类型别名
type User = {
id: number;
name: string;
};
// 接口
interface User {
id: number;
name: string;
}
4.实际应用场景
函数参数类型
typescript
interface Options {
verbose?: boolean;
}
function configure(options: Options) {
// ...
}
类实现
typescript
interface Car {
start(): void;
stop(): void;
}
class Tesla implements Car {
start() {
console.log("Starting Tesla");
}
stop() {
console.log("Stopping Tesla");
}
}
库中的类型定义
typescript
interface Promise<T> {
then<U>(onfulfilled?: (value: T) => U): Promise<U>;
// 使用内置的 Promise 类型
}