项目-求知久久-诱人的 TypeScript 视频教程

49 阅读4分钟

TypeScript 终极实战指南:从类型体操到企业级应用

一、TypeScript 核心特性精要

1. 类型系统深度解析

// 高级类型示例
type User<T extends boolean> = {
  id: T extends true ? string : number;
  name: string;
  age: number;
  roles: Array<'admin' | 'user' | 'guest'>;
  createdAt: Date;
  updatedAt?: Date; // 可选属性
}

// 条件类型与泛型约束
type AdminUser = User<true>;
type NormalUser = User<false>;

// 实用工具类型
type UserPreview = Pick<User<true>, 'id' | 'name'>;
type UserOptional = Partial<User<false>>;

2. 类型体操挑战

// 实现一个深度Readonly
type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
}

// 实现函数柯里化类型
type Curry<F extends (...args: any[]) => any> = 
  F extends (first: infer A, ...rest: infer B) => infer R
    ? B extends []
      ? F
      : (arg: A) => Curry<(...args: B) => R>
    : never;

// 测试用例
const add = (a: number, b: number, c: number): number => a + b + c;
type CurriedAdd = Curry<typeof add>; // (arg: number) => (arg: number) => (arg: number) => number

二、工程化实践

1. 现代前端配置

// tsconfig.json 最佳实践
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
    "types": ["vite/client"],
    "outDir": "dist",
    "declaration": true,
    "sourceMap": true
  },
  "include": ["src"],
  "exclude": ["node_modules"]
}

2. 类型定义管理策略

// 全局类型扩展示例
declare global {
  interface Window {
    __APP_CONFIG__: {
      apiBaseUrl: string;
      env: 'dev' | 'prod' | 'test';
    };
  }

  // 为第三方库扩展类型
  module 'lodash' {
    interface LoDashStatic {
      deepMapValues(obj: object, iteratee: Function): object;
    }
  }
}

// 类型守卫函数
function isError(value: unknown): value is Error {
  return value instanceof Error;
}

// 类型断言函数
function assertIsString(value: unknown): asserts value is string {
  if (typeof value !== 'string') {
    throw new Error('Not a string!');
  }
}

三、React + TypeScript 最佳实践

1. 组件类型设计

// 泛型组件示例
interface ListProps<T> {
  items: T[];
  renderItem: (item: T, index: number) => React.ReactNode;
  loading?: boolean;
  emptyComponent?: React.ReactElement;
}

function List<T>({ 
  items, 
  renderItem,
  loading = false,
  emptyComponent = <div>暂无数据</div>
}: ListProps<T>) {
  if (loading) return <Spinner />;
  if (!items.length) return emptyComponent;

  return (
    <ul className="list">
      {items.map((item, index) => (
        <li key={index}>{renderItem(item, index)}</li>
      ))}
    </ul>
  );
}

// 使用示例
<List<{ id: number; name: string }>
  items={users}
  renderItem={(user) => <span>{user.name}</span>}
/>

2. Redux Toolkit 类型安全

// store类型安全配置
import { configureStore, createSlice, PayloadAction } from '@reduxjs/toolkit';

interface CounterState {
  value: number;
  status: 'idle' | 'loading' | 'failed';
}

const initialState: CounterState = {
  value: 0,
  status: 'idle'
};

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload;
    },
  },
});

export const store = configureStore({
  reducer: {
    counter: counterSlice.reducer,
  },
});

// 推导RootState和AppDispatch类型
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

四、Node.js 后端开发

1. Express 类型安全路由

import express, { RequestHandler } from 'express';
import { ParamsDictionary } from 'express-serve-static-core';

interface User {
  id: number;
  name: string;
  email: string;
}

// 自定义Request类型
interface CreateUserBody {
  name: string;
  email: string;
  password: string;
}

const app = express();
app.use(express.json());

// 类型安全路由处理
app.post<ParamsDictionary, User, CreateUserBody>(
  '/users',
  async (req, res) => {
    // req.body已自动推断为CreateUserBody
    const newUser = await createUser(req.body);
    res.status(201).json(newUser);
  }
);

// 错误处理中间件
app.use(<RequestHandler<unknown, { error: string }>>(
  (err: Error, req, res, next) => {
    console.error(err.stack);
    res.status(500).json({ error: 'Something broke!' });
  }
));

2. Prisma 类型安全 ORM

// schema.prisma 模型定义
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  posts     Post[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

// 类型安全CRUD操作
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

async function createUserWithPost(userData: {
  email: string;
  name?: string;
  posts: {
    title: string;
    content?: string;
  }[];
}) {
  return prisma.user.create({
    data: {
      email: userData.email,
      name: userData.name,
      posts: {
        create: userData.posts,
      },
    },
    include: {
      posts: true,
    },
  });
}

五、性能优化与高级技巧

1. 类型级性能优化

// 避免过度使用枚举
// 改为使用联合类型
type Status = 'active' | 'inactive' | 'pending';

// 使用const断言
const ROLES = ['admin', 'user', 'guest'] as const;
type Role = typeof ROLES[number]; // "admin" | "user" | "guest"

// 条件类型分发优化
type Filter<T, U> = T extends any 
  ? T extends U 
    ? T 
    : never 
  : never;

// 使用接口合并替代交叉类型
interface UserBase {
  id: number;
}
interface UserWithName extends UserBase {
  name: string;
}

2. 编译时类型检查

// 自定义类型保护
function isStringArray(value: unknown): value is string[] {
  return Array.isArray(value) && value.every(item => typeof item === 'string');
}

// 编译时断言
type Assert<T extends true> = T;
type IsString<T> = T extends string ? true : false;
type Test = Assert<IsString<'hello'>>; // 通过
// type ErrorTest = Assert<IsString<123>>; // 报错

// 品牌类型(Branded Types)
type UserId = string & { readonly brand: unique symbol };
type PostId = string & { readonly brand: unique symbol };

function createUserId(id: string): UserId {
  return id as UserId;
}

function createPostId(id: string): PostId {
  return id as PostId;
}

// 这样可以防止UserId和PostId混用
const userId: UserId = createUserId('123');
const postId: PostId = createPostId('456');
// const error: UserId = postId; // 类型错误

六、测试与调试

1. 类型测试工具

// 使用dtslint进行类型测试
// example.test-d.ts
import { expectType } from 'tsd';

declare const user: User<true>;
expectType<string>(user.id); // 通过
// expectType<number>(user.id); // 报错

// 使用@ts-expect-error测试类型错误
// @ts-expect-error
const error: string = 123; // 测试这里应该报错

// 运行时类型校验(io-ts示例)
import * as t from 'io-ts';

const User = t.type({
  id: t.number,
  name: t.string,
  email: t.string,
});

type UserType = t.TypeOf<typeof User>; // 自动推导类型

const validateUser = (input: unknown): UserType => {
  return User.decode(input).getOrElseL((errors) => {
    throw new Error('Invalid user data');
  });
};

七、前沿技术整合

1. WebAssembly 类型支持

// wasm类型定义
declare module '*.wasm' {
  const url: string;
  export default url;
}

// wasm-loader类型
interface WasmModule {
  exports: {
    add: (a: number, b: number) => number;
    memory: WebAssembly.Memory;
  };
}

declare function loadWasm(path: string): Promise<WasmModule>;

// 使用示例
async function useWasm() {
  const wasm = await loadWasm('math.wasm');
  console.log(wasm.exports.add(2, 3));
}

2. 类型安全的 GraphQL

// 使用TypeGraphQL
import { ObjectType, Field, ID, Resolver, Query, Arg } from 'type-graphql';

@ObjectType()
class User {
  @Field(() => ID)
  id!: number;

  @Field()
  name!: string;

  @Field()
  email!: string;
}

@Resolver(User)
class UserResolver {
  @Query(() => User)
  async user(@Arg('id') id: number): Promise<User> {
    return getUserById(id);
  }
}

// 自动生成的类型
type GetUserQuery = {
  user: Pick<User, 'id' | 'name' | 'email'>;
};

通过系统学习TypeScript,开发者可以构建从简单脚本到企业级应用的全类型安全系统。建议的学习路径:

  1. 基础阶段:掌握类型系统与配置
  2. 进阶阶段:学习类型编程与工程化
  3. 专业方向:深入框架整合与性能优化
  4. 持续提升:参与DefinitelyTyped类型维护

关键实践原则

  • 优先使用类型推断而非显式注解
  • 保持类型声明与实际实现同步
  • 合理使用泛型避免重复代码
  • 建立严格的类型边界检查
  • 定期重构类型定义保持简洁