TypeScript实战指南
构建类型安全的JavaScript应用程序
TypeScript的优势
TypeScript是JavaScript的超集,为JavaScript添加了静态类型系统,提供了更好的代码提示、重构能力和错误检查。
类型安全: 在编译时捕获类型错误,避免运行时错误。
1. 基础类型
// 基础类型
let isDone: boolean = false;
let count: number = 42;
let name: string = "TypeScript";
// 数组
let list: number[] = [1, 2, 3];
let list2: Array<number> = [1, 2, 3];
// 元组
let tuple: [string, number] = ['hello', 10];
// 枚举
enum Color { Red, Green, Blue }
let color: Color = Color.Green;
// Any类型(谨慎使用)
let notSure: any = 4;
notSure = "maybe a string";
// Void类型
function warnUser(): void {
console.log("This is a warning message");
}
// Null和Undefined
let u: undefined = undefined;
let n: null = null;
2. 接口(Interface)
interface Person {
readonly id: number; // 只读属性
name: string;
age?: number; // 可选属性
// 方法签名
sayHello(): void;
}
// 使用接口
const person: Person = {
id: 1,
name: "Alice",
sayHello() {
console.log(`Hello, I'm ${this.name}`);
}
};
// 扩展接口
interface Employee extends Person {
employeeId: string;
department: string;
}
// 函数类型接口
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc = function(src, sub) {
return src.search(sub) > -1;
};
3. 泛型(Generics)
// 泛型函数
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("myString");
let output2 = identity("myString"); // 类型推断
// 泛型接口
interface GenericIdentityFn<T> {
(arg: T): T;
}
// 泛型类
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
// 泛型约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
4. 高级类型
// 联合类型
let value: string | number;
value = "hello";
value = 42;
// 交叉类型
interface A { a: number; }
interface B { b: string; }
type AB = A & B;
let ab: AB = { a: 1, b: "hello" };
// 类型别名
type StringOrNumber = string | number;
let value2: StringOrNumber;
// 类型断言
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
// 非空断言操作符
function liveDangerously(x?: number | null) {
console.log(x!.toFixed()); // ! 表示x一定不为null/undefined
}
// keyof操作符
interface Person {
name: string;
age: number;
location: string;
}
type PersonKeys = keyof Person; // "name" | "age" | "location"
// typeof操作符
let s = "hello";
let n: typeof s; // string
// 索引类型查询
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
5. 装饰器(Decorators)
// 类装饰器
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
// 方法装饰器
function enumerable(value: boolean) {
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
@enumerable(false)
greet() {
console.log(`Hello, ${this.name}`);
}
}
// 属性装饰器
function format(formatString: string) {
return function(target: any, propertyKey: string) {
// 存储元数据
Reflect.defineMetadata("format", formatString, target, propertyKey);
};
}
class Book {
@format("YYYY-MM-DD")
published: Date;
}
6. 实际项目配置
// tsconfig.json 示例
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"removeComments": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitThis": true,
"alwaysStrict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
7. 最佳实践
7.1 类型定义策略
- 优先使用interface而不是type alias
- 为第三方库创建声明文件
- 避免使用any类型
7.2 项目结构建议
src/
├── types/ // 类型定义
│ ├── api.d.ts
│ ├── global.d.ts
│ └── index.d.ts
├── interfaces/ // 接口定义
├── enums/ // 枚举定义
├── utils/ // 工具函数
├── services/ // 服务层
├── components/ // 组件
└── main.ts // 入口文件
总结
TypeScript不仅仅是JavaScript的类型扩展,更是一套完整的开发工具链。合理使用TypeScript可以显著提升代码质量、开发效率和团队协作能力。
关键建议:
- 从项目开始就使用TypeScript
- 保持类型定义的准确性和一致性
- 利用IDE的类型提示和重构功能
- 定期更新TypeScript配置