Appearance
TypeScript 实战指南
TypeScript 是 JavaScript 的超集,为 JavaScript 添加了类型系统。本文将介绍 TypeScript 的核心概念和实战技巧。
1. 类型系统
TypeScript 的核心特性是其类型系统,它可以帮助我们在编译时发现错误。
基本类型
typescript
// 基本类型
let isDone: boolean = false;
let decimal: number = 6;
let color: string = "blue";
let list: number[] = [1, 2, 3];
let tuple: [string, number] = ["hello", 10];
enum Color {Red, Green, Blue};
let c: Color = Color.Green;
let notSure: any = 4;
let nothing: void = undefined;
let nullValue: null = null;
let undefinedValue: undefined = undefined;
let object: object = {name: "John"};接口
接口用于定义对象的结构。
typescript
interface Person {
name: string;
age: number;
email?: string; // 可选属性
readonly id: number; // 只读属性
}
let person: Person = {
name: "John",
age: 30,
id: 123
};泛型
泛型允许我们编写可重用的组件。
typescript
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("myString");
let output2 = identity<number>(100);2. 高级类型
联合类型
联合类型表示一个值可以是几种类型中的一种。
typescript
let value: string | number;
value = "hello";
value = 42;交叉类型
交叉类型表示一个值同时具有多种类型的特性。
typescript
interface A {
a: number;
}
interface B {
b: string;
}
let value: A & B = {
a: 1,
b: "hello"
};类型守卫
类型守卫用于在运行时检查类型。
typescript
function isString(value: any): value is string {
return typeof value === "string";
}
function processValue(value: string | number) {
if (isString(value)) {
// 这里 value 被推断为 string 类型
console.log(value.toUpperCase());
} else {
// 这里 value 被推断为 number 类型
console.log(value.toFixed(2));
}
}3. 模块系统
TypeScript 使用 ES 模块系统。
typescript
// math.ts
export function add(a: number, b: number): number {
return a + b;
}
export interface Calculator {
add(a: number, b: number): number;
subtract(a: number, b: number): number;
}
// app.ts
import { add, Calculator } from './math';
console.log(add(1, 2)); // 3
class SimpleCalculator implements Calculator {
add(a: number, b: number): number {
return a + b;
}
subtract(a: number, b: number): number {
return a - b;
}
}4. 接口与类型别名
接口
接口主要用于定义对象的结构。
typescript
interface User {
id: number;
name: string;
email: string;
}
interface User {
age?: number; // 接口可以被合并
}类型别名
类型别名可以定义任何类型。
typescript
type UserId = number;
type UserName = string;
type User = {
id: UserId;
name: UserName;
email: string;
};
// 类型别名不能被合并
type User = {
age: number; // 错误:重复的类型别名
};5. 类型断言
类型断言用于告诉 TypeScript 编译器我们知道变量的类型。
typescript
// 尖括号语法
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
// as 语法
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;6. 枚举
枚举用于定义一组命名常量。
typescript
// 数字枚举
enum Direction {
Up = 1,
Down,
Left,
Right
}
// 字符串枚举
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT"
}
// 常量枚举
const enum Direction {
Up, Down, Left, Right
}7. 类
TypeScript 支持面向对象编程。
typescript
class Person {
private name: string;
protected age: number;
public email: string;
constructor(name: string, age: number, email: string) {
this.name = name;
this.age = age;
this.email = email;
}
getName(): string {
return this.name;
}
setName(name: string): void {
this.name = name;
}
}
class Employee extends Person {
private employeeId: number;
constructor(name: string, age: number, email: string, employeeId: number) {
super(name, age, email);
this.employeeId = employeeId;
}
getEmployeeId(): number {
return this.employeeId;
}
}8. 装饰器
装饰器用于修改类、方法、属性或参数的行为。
typescript
// 类装饰器
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 Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}9. 配置文件
TypeScript 使用 tsconfig.json 文件来配置编译选项。
json
{
"compilerOptions": {
"target": "ES2018",
"module": "commonjs",
"lib": ["ES2018"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}10. 与框架集成
与 React 集成
tsx
import React, { useState } from 'react';
interface Props {
name: string;
age: number;
}
const UserComponent: React.FC<Props> = ({ name, age }) => {
const [count, setCount] = useState<number>(0);
return (
<div>
<h1>{name}</h1>
<p>Age: {age}</p>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};与 Vue 集成
vue
<template>
<div>
<h1>{{ user.name }}</h1>
<p>Age: {{ user.age }}</p>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
interface User {
name: string;
age: number;
}
export default defineComponent({
name: 'UserComponent',
props: {
user: {
type: Object as () => User,
required: true
}
}
});
</script>11. 最佳实践
- 使用严格模式:在
tsconfig.json中设置"strict": true - 明确类型:为变量、函数参数和返回值指定类型
- 使用接口:定义对象的结构
- 使用泛型:编写可重用的代码
- 使用类型守卫:在运行时检查类型
- 避免使用 any:尽量使用具体的类型
- 使用枚举:定义一组相关的常量
- 使用装饰器:增强类和方法的功能
- 合理使用类型断言:仅在必要时使用
- 保持代码风格一致:使用 ESLint 和 Prettier
12. 性能优化
- 使用 const 枚举:减少运行时开销
- 使用 readonly:防止不必要的修改
- 使用类型守卫:避免运行时类型检查
- 合理使用泛型:避免过度使用泛型
- 使用模块:按需导入模块
- 使用 tree shaking:移除未使用的代码
13. 常见问题
类型错误
typescript
// 错误:类型 'string' 不能赋值给类型 'number'
let num: number = "123";
// 正确
let num: number = parseInt("123");模块解析
typescript
// 错误:找不到模块 './math'
import { add } from './math';
// 正确:添加 .ts 扩展名或配置模块解析
import { add } from './math.ts';类型定义
typescript
// 错误:找不到名称 'Window'
const window: Window = globalThis;
// 正确:安装类型定义
// npm install --save-dev @types/node14. 工具推荐
- tsc:TypeScript 编译器
- ts-node:直接运行 TypeScript 文件
- ESLint:代码检查
- Prettier:代码格式化
- VS Code:TypeScript 支持
- TypeScript Playground:在线 TypeScript 编辑器
15. 总结
TypeScript 为 JavaScript 添加了类型系统,使我们能够编写更加安全、可维护的代码。通过学习和使用 TypeScript,我们可以提高代码质量,减少运行时错误,提高开发效率。
TypeScript 已经成为前端开发的主流语言,许多大型项目和框架都在使用 TypeScript。掌握 TypeScript 是现代前端开发者的必备技能。