共计 13295 个字符,预计需要花费 34 分钟才能阅读完成。
目录
TypeScript 简介
TypeScript 是 JavaScript 的超集,添加了静态类型系统。它由微软开发,可以在任何支持 JavaScript 的地方运行。
主要特性
- 静态类型检查:在编译时发现错误
- 类型推断:自动推断变量类型
- 接口和泛型:更好的代码组织和复用
- ES6+ 特性支持:支持最新的 JavaScript 特性
- 工具支持:更好的 IDE 支持和代码补全
环境搭建
安装 TypeScript
# 全局安装
npm install -g typescript
# 或者作为项目依赖安装
npm install --save-dev typescript
验证安装
tsc --version
创建第一个 TypeScript 文件
创建 hello.ts:
function greet(name: string): string {return `Hello, ${name}!`;
}
const message = greet("TypeScript");
console.log(message);
编译 TypeScript
# 编译单个文件
tsc hello.ts
# 使用配置文件编译
tsc
tsconfig.json 配置
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
基础类型
基本类型
// 布尔值
let isDone: boolean = false;
// 数字
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
// 字符串
let color: string = "blue";
color = 'red';
// 模板字符串
let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${fullName}. I'll be ${age + 1} years old next month.`;
// 数组
let list1: number[] = [1, 2, 3];
let list2: Array<number> = [1, 2, 3]; // 泛型语法
// 元组
let tuple: [string, number];
tuple = ["hello", 10]; // OK
// tuple = [10, "hello"]; // Error
// 枚举
enum Color {
Red,
Green,
Blue
}
let c: Color = Color.Green;
enum ColorWithValues {
Red = 1,
Green = 2,
Blue = 4
}
// Any
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false;
// Void
function warnUser(): void {console.log("This is my warning message");
}
// Null 和 Undefined
let u: undefined = undefined;
let n: null = null;
// Never
function error(message: string): never {throw new Error(message);
}
// Object
declare function create(o: object | null): void;
create({prop: 0}); // OK
create(null); // OK
// create(42); // Error
// 类型断言
let someValue: any = "this is a string";
let strLength1: number = (someValue as string).length;
let strLength2: number = (<string>someValue).length;
联合类型和类型别名
// 联合类型
let union: string | number;
union = "hello";
union = 42;
// union = true; // Error
// 类型别名
type StringOrNumber = string | number;
let value: StringOrNumber;
value = "hello";
value = 123;
// 字面量类型
type Direction = "left" | "right" | "up" | "down";
let move: Direction = "left";
// move = "diagonal"; // Error
// 交叉类型
interface BusinessPartner {
name: string;
credit: number;
}
interface Identity {
id: number;
name: string;
}
type Employee = Identity & BusinessPartner;
let employee: Employee = {
id: 1,
name: "John",
credit: 1000
};
接口
基础接口
// 基础接口
interface Person {
readonly id: number; // 只读属性
name: string;
age?: number; // 可选属性
}
function printPerson(person: Person): void {console.log(`ID: ${person.id}, Name: ${person.name}`);
if (person.age) {console.log(`Age: ${person.age}`);
}
}
let john: Person = {
id: 1,
name: "John"
};
// 函数类型接口
interface SearchFunc {(source: string, subString: string): boolean;
}
let mySearch: SearchFunc = function(src: string, sub: string): boolean {return src.search(sub) > -1;
};
// 可索引类型接口
interface StringArray {[index: number]: string;
}
let myArray: StringArray = ["Bob", "Fred"];
let myStr: string = myArray[0];
接口继承和实现
// 接口继承
interface Shape {color: string;}
interface Square extends Shape {sideLength: number;}
let square = {} as Square;
square.color = "blue";
square.sideLength = 10;
// 多继承
interface PenStroke {penWidth: number;}
interface SquareWithPen extends Shape, PenStroke {sideLength: number;}
// 类实现接口
interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
}
class Clock implements ClockInterface {currentTime: Date = new Date();
setTime(d: Date) {this.currentTime = d;}
constructor(h: number, m: number) {}}
类
基础类
class Animal {
// 属性
private name: string; // 私有属性,只能在类内部访问
protected age: number; // 受保护属性,可以在子类中访问
public readonly species: string; // 公开只读属性
// 静态属性
static numberOfAnimals: number = 0;
// 构造函数
constructor(name: string, age: number, species: string) {
this.name = name;
this.age = age;
this.species = species;
Animal.numberOfAnimals++;
}
// 方法
public move(distanceInMeters: number = 0): void {console.log(`${this.name} moved ${distanceInMeters}m.`);
}
// 获取私有属性
public getName(): string {return this.name;}
// 静态方法
static getNumberOfAnimals(): number {return Animal.numberOfAnimals;}
}
继承和多态
// 继承
class Dog extends Animal {
private breed: string;
constructor(name: string, age: number, breed: string) {super(name, age, "Dog"); // 调用父类构造函数
this.breed = breed;
}
// 方法重写
public move(distanceInMeters: number = 5): void {console.log("Running...");
super.move(distanceInMeters); // 调用父类方法
}
// 新方法
public bark(): void {console.log("Woof! Woof!");
}
public getBreed(): string {return this.breed;}
}
// 使用
const dog = new Dog("Buddy", 3, "Golden Retriever");
dog.move(10);
dog.bark();
console.log(Animal.getNumberOfAnimals());
抽象类
abstract class Department {constructor(public name: string) {}
// 抽象方法,必须在子类中实现
abstract printMeeting(): void;
// 具体方法
printName(): void {console.log("Department name:" + this.name);
}
}
class AccountingDepartment extends Department {constructor() {super("Accounting and Auditing");
}
printMeeting(): void {console.log("The Accounting Department meets each Monday at 10am.");
}
generateReports(): void {console.log("Generating accounting reports...");
}
}
// 使用
let department: Department; // 允许创建对抽象类型的引用
// department = new Department(); // 错误:不能创建抽象类的实例
department = new AccountingDepartment(); // 允许对抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
// department.generateReports(); // 错误:方法在声明的抽象类中不存在
访问器
class Employee {
private _fullName: string = "";
get fullName(): string {return this._fullName;}
set fullName(newName: string) {if (newName && newName.length > 3) {this._fullName = newName;} else {console.log("Error: Name must be longer than 3 characters");
}
}
}
let employee = new Employee();
employee.fullName = "John Doe";
console.log(employee.fullName);
函数
函数类型
// 函数声明
function add(x: number, y: number): number {return x + y;}
// 函数表达式
let myAdd = function(x: number, y: number): number {return x + y;};
// 箭头函数
let myAddArrow = (x: number, y: number): number => x + y;
// 可选参数和默认参数
function buildName(firstName: string, lastName?: string, middleName: string = ""): string {if (lastName) {return `${firstName} ${middleName} ${lastName}`;
}
return firstName;
}
// 剩余参数
function buildNameRest(firstName: string, ...restOfName: string[]): string {return firstName + "" + restOfName.join(" ");
}
// 函数重载
function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {if (d !== undefined && y !== undefined) {return new Date(y, mOrTimestamp, d);
} else {return new Date(mOrTimestamp);
}
}
const d1 = makeDate(12345678);
const d2 = makeDate(5, 5, 2020);
// const d3 = makeDate(1, 3); // Error: 没有需要 2 参数的重载
this 和上下文
interface Card {
suit: string;
card: number;
}
interface Deck {suits: string[];
cards: number[];
createCardPicker(this: Deck): () => Card;}
let deck: Deck = {suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function(this: Deck) {return () => {let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
}
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
console.log("card:" + pickedCard.card + "of" + pickedCard.suit);
泛型
基础泛型
// 泛型函数
function identity<T>(arg: T): T {return arg;}
let output1 = identity<string>("myString");
let output2 = identity("myString"); // 类型推断
// 泛型接口
interface GenericIdentityFn<T> {(arg: T): T;
}
let myIdentity: GenericIdentityFn<number> = identity;
// 泛型类
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
constructor(zeroValue: T, add: (x: T, y: T) => T) {
this.zeroValue = zeroValue;
this.add = add;
}
}
let myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y);
泛型约束
interface Lengthwise {length: number;}
function loggingIdentity<T extends Lengthwise>(arg: T): T {console.log(arg.length); // 现在我们知道 arg 有 length 属性
return arg;
}
// loggingIdentity(3); // Error: number 没有 length 属性
loggingIdentity({length: 10, value: 3}); // OK
// 在泛型约束中使用类型参数
function getProperty<T, K extends keyof T>(obj: T, key: K) {return obj[key];
}
let x = {a: 1, b: 2, c: 3, d: 4};
getProperty(x, "a"); // OK
// getProperty(x, "m"); // Error: 参数类型 '"m"' 不能赋值给参数类型 '"a" | "b" | "c" | "d"'
泛型工具类型
interface Todo {
title: string;
description: string;
completed: boolean;
}
// Partial - 所有属性变为可选
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {return { ...todo, ...fieldsToUpdate};
}
// Readonly - 所有属性变为只读
const todo: Readonly<Todo> = {
title: "Delete inactive users",
description: "...",
completed: false
};
// todo.title = "Hello"; // Error: 无法分配到 "title",因为它是只读属性
// Pick - 从类型中选择一组属性
type TodoPreview = Pick<Todo, "title" | "completed">;
const preview: TodoPreview = {
title: "Clean room",
completed: false
};
// Omit - 从类型中排除一组属性
type TodoInfo = Omit<Todo, "completed">;
const info: TodoInfo = {
title: "Pick up kids",
description: "Kindergarten closes at 5pm"
};
模块系统
导出和导入
// math.ts - 导出
export const PI = 3.14;
export interface Circle {radius: number;}
export function calculateCircumference(diameter: number): number {return diameter * PI;}
// 默认导出
export default class Calculator {static add(x: number, y: number): number {return x + y;}
}
// app.ts - 导入
import Calculator, {PI, Circle, calculateCircumference} from './math';
const circle: Circle = {radius: 10};
console.log(calculateCircumference(circle.radius * 2));
console.log(Calculator.add(5, 3));
// 重新导出
export {PI as MathPI} from './math';
命名空间
namespace Validation {
export interface StringValidator {isAcceptable(s: string): boolean;
}
const lettersRegexp = /^[A-Za-z]+$/;
const numberRegexp = /^[0-9]+$/;
export class LettersOnlyValidator implements StringValidator {isAcceptable(s: string) {return lettersRegexp.test(s);
}
}
export class ZipCodeValidator implements StringValidator {isAcceptable(s: string) {return s.length === 5 && numberRegexp.test(s);
}
}
}
// 使用命名空间
let validators: {[s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();
类型进阶
条件类型
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
T extends undefined ? "undefined" :
T extends Function ? "function" :
"object";
type T0 = TypeName<string>; // "string"
type T1 = TypeName<"a">; // "string"
type T2 = TypeName<true>; // "boolean"
type T3 = TypeName<() => void>; // "function"
type T4 = TypeName<string[]>; // "object"
// 分布式条件类型
type ToArray<T> = T extends any ? T[] : never;
type StrArrOrNumArr = ToArray<string | number>; // string[] | number[]
// 排除 null 和 undefined
type NonNullable<T> = T extends null | undefined ? never : T;
type T5 = NonNullable<string | number | undefined>; // string | number
映射类型
interface Person {
name: string;
age: number;
location: string;
}
// 使所有属性变为只读
type ReadonlyPerson = Readonly<Person>;
// 使所有属性变为可选
type PartialPerson = Partial<Person>;
// 选择特定属性
type PersonKeys = keyof Person; // "name" | "age" | "location"
// 自定义映射类型
type Optional<T> = {[P in keyof T]?: T[P];
};
type Nullable<T> = {[P in keyof T]: T[P] | null;
};
// 移除只读修饰符
type CreateMutable<T> = {-readonly [P in keyof T]: T[P];
};
// 移除可选修饰符
type Concrete<T> = {[P in keyof T]-?: T[P];
};
模板字面量类型
type World = "world";
type Greeting = `hello ${World}`; // "hello world"
type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
// "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"
// 字符串操作类型
type Getter<T extends string> = `get${Capitalize<T>}`;
type Setter<T extends string> = `set${Capitalize<T>}`;
type Name = "name";
type NameAccessors = Getter<Name> | Setter<Name>; // "getName" | "setName"
配置与工程化
完整 tsconfig.json
{
"compilerOptions": {
/* 基本选项 */
"target": "ES2020", // 编译目标
"module": "CommonJS", // 模块系统
"lib": ["ES2020", "DOM"], // 包含的库文件
"outDir": "./dist", // 输出目录
"rootDir": "./src", // 源文件目录
/* 严格类型检查选项 */
"strict": true, // 启用所有严格类型检查选项
"noImplicitAny": true, // 禁止隐式 any 类型
"strictNullChecks": true, // 严格的 null 检查
"strictFunctionTypes": true, // 严格的函数类型检查
"strictBindCallApply": true, // 严格的 bind/call/apply 检查
"strictPropertyInitialization": true, // 严格的属性初始化检查
"noImplicitThis": true, // 禁止隐式的 this 类型
"alwaysStrict": true, // 以严格模式解析并为每个源文件生成 "use strict"
/* 额外检查 */
"noUnusedLocals": true, // 报告未使用的局部变量的错误
"noUnusedParameters": true, // 报告未使用的参数的错误
"noImplicitReturns": true, // 不是函数中的所有代码路径都返回值时报错
"noFallthroughCasesInSwitch": true, // 报告 switch 语句的 fallthrough 错误
/* 模块解析选项 */
"moduleResolution": "node", // 模块解析策略
"baseUrl": "./", // 解析非相对模块名的基准目录
"paths": { // 模块名到基于 baseUrl 的路径映射
"@/*": ["src/*"],
"@/components/*": ["src/components/*"]
},
"esModuleInterop": true, // 为导入 CommonJS 模块提供兼容性
"allowSyntheticDefaultImports": true, // 允许从没有默认导出的模块进行默认导入
/* Source Map 选项 */
"sourceMap": true, // 生成相应的 .map 文件
"declaration": true, // 生成相应的 .d.ts 文件
"declarationMap": true, // 为声明文件生成 sourcemap
/* 实验性选项 */
"experimentalDecorators": true, // 启用装饰器
"emitDecoratorMetadata": true, // 为装饰器提供元数据支持
/* 高级选项 */
"skipLibCheck": true, // 跳过所有声明文件的类型检查
"forceConsistentCasingInFileNames": true // 禁止对同一文件使用不一致大小写的引用
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist",
"**/*.test.ts"
]
}
与 React 集成
// React 组件示例
import React, {useState, useEffect} from 'react';
interface User {
id: number;
name: string;
email: string;
}
interface UserListProps {users: User[];
onUserSelect: (user: User) => void;
}
const UserList: React.FC<UserListProps> = ({users, onUserSelect}) => {const [selectedUserId, setSelectedUserId] = useState<number | null>(null);
const handleUserClick = (user: User) => {setSelectedUserId(user.id);
onUserSelect(user);
};
return (
<div>
<h2>User List</h2>
<ul>
{users.map(user => (
<li
key={user.id}
onClick={() => handleUserClick(user)}
style={{
cursor: 'pointer',
backgroundColor: selectedUserId === user.id ? '#f0f0f0' : 'transparent'
}}
>
{user.name} - {user.email}
</li>
))}
</ul>
</div>
);
};
// 自定义 Hook
function useUsers() {const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {const fetchUsers = async () => {
try {setLoading(true);
// 模拟 API 调用
const response = await fetch('/api/users');
const data = await response.json();
setUsers(data);
} catch (err) {setError(err.message);
} finally {setLoading(false);
}
};
fetchUsers();}, []);
return {users, loading, error};
}
export default UserList;
最佳实践
- 启用严格模式:始终在
tsconfig.json中设置"strict": true - 使用明确的类型:避免过度使用
any类型 - 利用类型推断:在明显的地方让 TypeScript 推断类型
- 使用接口定义对象形状:而不是内联类型注解
- 利用泛型提高代码复用性
- 使用只读数组和元组:确保数据不可变性
- 使用 const 断言:用于字面量类型
// 好的实践
interface User {
readonly id: number;
name: string;
email: string;
}
type UserList = ReadonlyArray<User>;
// const 断言
const positions = ["left", "right", "top", "bottom"] as const;
type Position = typeof positions[number]; // "left" | "right" | "top" | "bottom"
正文完

