TypeScript 日常工作笔记
1. 基础类型
1.1 基本类型
解释: TypeScript 提供了比 JavaScript 更丰富的类型系统。
// 基本类型
let str: string = "hello"; // 字符串
let num: number = 42; // 数字
let bool: boolean = true; // 布尔值
let n: null = null; // null
let u: undefined = undefined; // undefined
let sym: symbol = Symbol("id"); // Symbol
let big: bigint = 123n; // BigInt
// 数组类型
let arr1: number[] = [1, 2, 3]; // 数字数组
let arr2: Array<string> = ["a", "b"]; // 字符串数组
// 元组类型
let tuple: [string, number] = ["张三", 25]; // 固定长度和类型的数组
// 枚举类型
enum Color {
Red = "RED",
Green = "GREEN",
Blue = "BLUE"
}
let color: Color = Color.Red;
1.2 对象类型
解释: 对象类型定义了对象的结构和属性类型。
// 对象类型定义
interface Person {
name: string;
age: number;
email?: string; // 可选属性
readonly id: number; // 只读属性
}
// 使用接口
const person: Person = {
name: "张三",
age: 25,
id: 1
};
// 类型别名
type Point = {
x: number;
y: number;
};
// 联合类型
type Status = "pending" | "success" | "error";
let status: Status = "pending";
// 交叉类型
type Employee = Person & {
department: string;
salary: number;
};
1.3 函数类型
解释: TypeScript 可以为函数参数和返回值指定类型。
// 函数类型定义
function add(a: number, b: number): number {
return a + b;
}
// 箭头函数类型
const multiply: (a: number, b: number) => number = (a, b) => a * b;
// 函数接口
interface MathFunc {
(a: number, b: number): number;
}
// 可选参数和默认参数
function greet(name: string, greeting: string = "Hello"): string {
return `${greeting}, ${name}!`;
}
// 剩余参数
function sum(...numbers: number[]): number {
return numbers.reduce((acc, num) => acc + num, 0);
}
// 函数重载
function process(value: string): string;
function process(value: number): number;
function process(value: string | number): string | number {
if (typeof value === "string") {
return value.toUpperCase();
} else {
return value * 2;
}
}
2. 高级类型
2.1 泛型
解释: 泛型允许创建可重用的组件,这些组件可以处理多种类型。
// 泛型函数
function identity<T>(arg: T): T {
return arg;
}
const result1 = identity<string>("hello");
const result2 = identity(42); // 类型推断
// 泛型接口
interface Container<T> {
value: T;
getValue(): T;
}
// 泛型类
class Queue<T> {
private data: T[] = [];
push(item: T): void {
this.data.push(item);
}
pop(): T | undefined {
return this.data.shift();
}
}
const stringQueue = new Queue<string>();
stringQueue.push("hello");
2.2 条件类型
解释: 条件类型根据输入类型选择输出类型。
// 基本条件类型
type NonNullable<T> = T extends null | undefined ? never : T;
type T1 = NonNullable<string | number | null>; // string | number
// 条件类型与 infer
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type FuncReturnType = ReturnType<() => string>; // string
// 映射类型
type Partial<T> = {
[P in keyof T]?: T[P];
};
type Required<T> = {
[P in keyof T]-?: T[P];
};
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
// 使用示例
interface User {
name: string;
age: number;
email?: string;
}
type PartialUser = Partial<User>; // 所有属性变为可选
type RequiredUser = Required<User>; // 所有属性变为必需
type ReadonlyUser = Readonly<User>; // 所有属性变为只读
2.3 工具类型
解释: TypeScript 提供了许多内置的工具类型。
// Pick - 选择部分属性
type UserBasic = Pick<User, 'name' | 'age'>;
// Omit - 排除部分属性
type UserWithoutEmail = Omit<User, 'email'>;
// Record - 创建键值对类型
type UserRoles = Record<string, string[]>;
// Exclude - 排除联合类型中的某些类型
type NonNull = Exclude<string | number | null, null>; // string | number
// Extract - 提取联合类型中的某些类型
type StringOrNumber = Extract<string | number | boolean, string | number>; // string | number
// Parameters - 获取函数参数类型
type FuncParams = Parameters<(name: string, age: number) => void>; // [string, number]
// InstanceType - 获取构造函数实例类型
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}
type AnimalInstance = InstanceType<typeof Animal>; // Animal
3. 接口与类型
3.1 接口扩展
解释: 接口可以继承和扩展其他接口。
// 基本接口
interface Shape {
color: string;
}
// 接口扩展
interface Square extends Shape {
sideLength: number;
}
// 多接口扩展
interface Circle extends Shape {
radius: number;
}
interface ColoredCircle extends Circle {
borderColor: string;
}
// 实现接口
class MySquare implements Square {
constructor(public color: string, public sideLength: number) {}
}
// 接口合并
interface Box {
height: number;
width: number;
}
interface Box {
scale: number;
}
// 最终 Box 接口包含 height, width, scale 三个属性
3.2 类型别名
解释: 类型别名可以为类型创建新名称。
// 基本类型别名
type Name = string;
type Age = number;
type UserId = string | number;
// 联合类型别名
type Status = "loading" | "success" | "error";
// 函数类型别名
type EventHandler = (event: Event) => void;
type AsyncFunction<T> = () => Promise<T>;
// 对象类型别名
type Point = {
x: number;
y: number;
};
// 映射类型别名
type Optional<T> = {
[K in keyof T]?: T[K];
};
// 条件类型别名
type IsString<T> = T extends string ? true : false;
4. 类与面向对象
4.1 类定义
解释: TypeScript 的类支持访问修饰符、抽象类等特性。
// 基本类
class Animal {
private name: string;
protected age: number;
public species: string;
constructor(name: string, age: number, species: string) {
this.name = name;
this.age = age;
this.species = species;
}
public makeSound(): void {
console.log("Some sound");
}
protected getInfo(): string {
return `${this.name} is ${this.age} years old`;
}
}
// 继承
class Dog extends Animal {
private breed: string;
constructor(name: string, age: number, breed: string) {
super(name, age, "Dog");
this.breed = breed;
}
public makeSound(): void {
console.log("Woof!");
}
public getBreedInfo(): string {
return `${this.getInfo()}, breed: ${this.breed}`;
}
}
// 抽象类
abstract class Vehicle {
abstract start(): void;
stop(): void {
console.log("Vehicle stopped");
}
}
class Car extends Vehicle {
start(): void {
console.log("Car started");
}
}
4.2 访问修饰符
解释: TypeScript 提供了三种访问修饰符来控制类成员的可见性。
class Example {
public publicField: string = "public"; // 任何地方都可以访问
private privateField: string = "private"; // 只能在类内部访问
protected protectedField: string = "protected"; // 只能在类内部和子类中访问
public publicMethod(): void {
console.log(this.privateField); // 可以访问私有成员
}
private privateMethod(): void {
console.log("private method");
}
protected protectedMethod(): void {
console.log("protected method");
}
}
class SubExample extends Example {
public test(): void {
console.log(this.publicField); // 可以访问
console.log(this.protectedField); // 可以访问
// console.log(this.privateField); // 错误:不能访问私有成员
}
}
5. 模块与命名空间
5.1 模块导入导出
解释: TypeScript 支持 ES6 模块语法,可以导入导出类型和值。
// math.ts - 导出模块
export interface Point {
x: number;
y: number;
}
export function add(a: number, b: number): number {
return a + b;
}
export const PI = 3.14159;
export default class Calculator {
add(a: number, b: number): number {
return a + b;
}
}
// main.ts - 导入模块
import Calculator, { add, PI, Point } from './math';
const calc = new Calculator();
const result = calc.add(5, 3);
const point: Point = { x: 10, y: 20 };
// 重命名导入
import { add as addNumbers } from './math';
// 导入所有内容
import * as MathUtils from './math';
5.2 命名空间
解释: 命名空间提供了一种组织代码的方式,避免全局命名空间污染。
// 基本命名空间
namespace Validation {
export interface StringValidator {
isValid(s: string): boolean;
}
export class EmailValidator implements StringValidator {
isValid(s: string): boolean {
return s.includes('@');
}
}
export class PhoneValidator implements StringValidator {
isValid(s: string): boolean {
return /^\d{11}$/.test(s);
}
}
}
// 使用命名空间
const emailValidator = new Validation.EmailValidator();
const isValid = emailValidator.isValid("test@example.com");
// 嵌套命名空间
namespace Geometry {
export namespace Shapes {
export class Circle {
constructor(public radius: number) {}
area(): number {
return Math.PI * this.radius ** 2;
}
}
}
}
const circle = new Geometry.Shapes.Circle(5);
6. 类型断言与类型守卫
6.1 类型断言
解释: 类型断言告诉 TypeScript 编译器你比它更了解某个值的类型。
// 基本类型断言
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;
// 另一种语法
let strLength2: number = (<string>someValue).length;
// 非空断言
function processName(name?: string) {
console.log(name!.toUpperCase()); // 断言 name 不为 null/undefined
}
// 类型断言函数
function isString(value: unknown): value is string {
return typeof value === "string";
}
function processValue(value: unknown) {
if (isString(value)) {
console.log(value.toUpperCase()); // TypeScript 知道 value 是 string
}
}
6.2 类型守卫
解释: 类型守卫是运行时检查,用于缩小类型范围。
// typeof 类型守卫
function process(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase();
} else {
return value.toFixed(2);
}
}
// instanceof 类型守卫
class Dog {
bark() {
return "Woof!";
}
}
class Cat {
meow() {
return "Meow!";
}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
return animal.bark();
} else {
return animal.meow();
}
}
// in 操作符类型守卫
interface Bird {
fly(): void;
layEggs(): void;
}
interface Fish {
swim(): void;
layEggs(): void;
}
function move(animal: Bird | Fish) {
if ("fly" in animal) {
animal.fly();
} else {
animal.swim();
}
}
7. 实用类型技巧
7.1 条件类型与映射
解释: 结合条件类型和映射类型可以创建强大的类型工具。
// 深度可选
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
// 深度只读
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
// 提取函数参数类型
type Parameters<T> = T extends (...args: infer P) => any ? P : never;
// 提取函数返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
// 提取 Promise 类型
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
// 使用示例
interface User {
name: string;
profile: {
age: number;
email: string;
};
}
type PartialUser = DeepPartial<User>;
// 等价于:
// {
// name?: string;
// profile?: {
// age?: number;
// email?: string;
// };
// }
7.2 模板字面量类型
解释: TypeScript 4.1+ 支持模板字面量类型,可以基于字符串字面量创建类型。
// 基本模板字面量类型
type Greeting = "Hello" | "Hi" | "Welcome";
type Name = "World" | "TypeScript" | "Developer";
type GreetingMessage = `${Greeting} ${Name}!`;
// 字符串操作类型
type Uppercase<S extends string> = S extends `${infer F}${infer R}`
? `${Uppercase<F>}${Uppercase<R>}`
: S;
type Lowercase<S extends string> = S extends `${infer F}${infer R}`
? `${Lowercase<F>}${Lowercase<R>}`
: S;
// 字符串替换
type Replace<S extends string, From extends string, To extends string> =
S extends `${infer Prefix}${From}${infer Suffix}`
? `${Prefix}${To}${Suffix}`
: S;
// 使用示例
type EventName = "click" | "hover" | "focus";
type HandlerName = `on${Capitalize<EventName>}`;
// 结果: "onClick" | "onHover" | "onFocus"
8. 错误处理与调试
8.1 严格模式
解释: TypeScript 的严格模式可以帮助捕获更多潜在错误。
// tsconfig.json 中的严格选项
{
"compilerOptions": {
"strict": true, // 启用所有严格检查
"noImplicitAny": true, // 禁止隐式 any
"strictNullChecks": true, // 严格的 null 检查
"strictFunctionTypes": true, // 严格的函数类型检查
"strictBindCallApply": true, // 严格的 bind/call/apply 检查
"strictPropertyInitialization": true, // 严格的属性初始化检查
"noImplicitReturns": true, // 禁止隐式返回
"noFallthroughCasesInSwitch": true, // 禁止 switch 中的 fallthrough
"noUncheckedIndexedAccess": true // 禁止未检查的索引访问
}
}
// 严格 null 检查示例
function processName(name: string | null) {
if (name === null) {
return "Anonymous";
}
return name.toUpperCase(); // TypeScript 知道 name 不是 null
}
8.2 类型错误处理
解释: 处理 TypeScript 编译错误的最佳实践。
// 使用类型断言处理第三方库
declare const externalLib: any;
const data = externalLib.getData() as MyDataType;
// 使用 unknown 类型
function processUnknownData(data: unknown) {
if (typeof data === "object" && data !== null) {
const obj = data as Record<string, unknown>;
if ("name" in obj && typeof obj.name === "string") {
console.log(obj.name.toUpperCase());
}
}
}
// 使用 satisfies 操作符(TypeScript 4.9+)
const config = {
apiUrl: "https://api.example.com",
timeout: 5000,
retries: 3
} satisfies ApiConfig;
// 使用 const 断言
const colors = ["red", "green", "blue"] as const;
type Color = typeof colors[number]; // "red" | "green" | "blue"
9. 项目实践
9.1 类型定义文件
解释: 为第三方库或项目创建类型定义。
// types/global.d.ts
declare global {
interface Window {
myCustomProperty: string;
}
namespace NodeJS {
interface ProcessEnv {
NODE_ENV: "development" | "production" | "test";
API_URL: string;
}
}
}
export {};
// types/api.d.ts
export interface ApiResponse<T = any> {
success: boolean;
data: T;
message: string;
code: number;
}
export interface PaginatedResponse<T> extends ApiResponse<T[]> {
pagination: {
page: number;
pageSize: number;
total: number;
totalPages: number;
};
}
// types/user.d.ts
export interface User {
id: number;
name: string;
email: string;
avatar?: string;
createdAt: string;
updatedAt: string;
}
export interface CreateUserRequest {
name: string;
email: string;
password: string;
}
export interface UpdateUserRequest extends Partial<CreateUserRequest> {
id: number;
}
9.2 实用工具类型
解释: 创建项目中常用的工具类型。
// utils/types.ts
// 提取 API 响应类型
type ApiResponseType<T> = T extends Promise<ApiResponse<infer U>> ? U : never;
// 提取表单字段类型
type FormFields<T> = {
[K in keyof T]: T[K] extends string | number | boolean ? T[K] : never;
};
// 创建表单验证规则类型
type ValidationRules<T> = {
[K in keyof T]?: {
required?: boolean;
min?: number;
max?: number;
pattern?: RegExp;
message?: string;
};
};
// 提取事件处理函数类型
type EventHandler<T> = (event: T) => void;
// 创建状态类型
type LoadingState = "idle" | "loading" | "success" | "error";
type StateWithLoading<T> = {
data: T | null;
loading: LoadingState;
error: string | null;
};
// 使用示例
interface UserForm {
name: string;
email: string;
age: number;
}
type UserFormFields = FormFields<UserForm>;
type UserValidationRules = ValidationRules<UserForm>;
10. 常见问题与解决方案
10.1 类型推断问题
// 问题:类型推断不准确
const items = [1, 2, 3, "hello"]; // 推断为 (number | string)[]
// 解决方案:明确类型
const items: number[] = [1, 2, 3];
const mixedItems: (number | string)[] = [1, 2, 3, "hello"];
10.2 泛型约束
// 问题:泛型类型过于宽泛
function getProperty<T>(obj: T, key: string) {
return obj[key]; // 错误:不能保证 key 存在于 obj 中
}
// 解决方案:添加约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
10.3 异步函数类型
// 问题:异步函数返回类型不明确
async function fetchData() {
const response = await fetch('/api/data');
return response.json(); // 返回 any
}
// 解决方案:明确返回类型
async function fetchData(): Promise<User[]> {
const response = await fetch('/api/data');
return response.json();
}
本笔记涵盖了 TypeScript 的核心概念和实用技巧,适合日常开发查阅。建议结合官方文档和实际项目实践深入学习。