TypeScript 进阶指南(六):实战中的高级类型模式


TypeScript 进阶指南(六):实战中的高级类型模式


1. 类型安全的状态管理(Redux Toolkit)
// 定义 action 类型
type CounterAction =
  | { type: 'INCREMENT'; payload: number }    // 携带数字载荷
  | { type: 'DECREMENT'; payload: number }    // 统一载荷类型
  | { type: 'RESET' };                        // 无载荷动作

// 类型化 reducer 函数
const counterReducer = (
  state: number = 0,
  action: CounterAction                       // 确保处理所有 action 类型
): number => {
  switch (action.type) {
    case 'INCREMENT':
      return state + action.payload;          // 自动推断 payload 为 number
    case 'DECREMENT':
      return state - action.payload;
    case 'RESET':
      return 0;
    default:
      return state;
  }
};

// 创建类型化 hooks
const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
const useAppDispatch = () => useDispatch<AppDispatch>();

// 组件中使用
const CounterComponent = () => {
  const count = useAppSelector(state => state.counter);
  const dispatch = useAppDispatch();

  return (
    <div>
      <button onClick={() => dispatch({ type: 'INCREMENT', payload: 5 })}>
        +5
      </button>
      <span>{count}</span>
    </div>
  );
};

2. 高级类型工具实战
// 深度可选类型(递归处理对象属性)
type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

interface UserProfile {
  id: number;
  details: {
    name: string;
    address?: {
      city: string;
      street: string;
    };
  };
}

// 允许嵌套属性可选
const partialProfile: DeepPartial<UserProfile> = {
  details: { 
    address: { city: 'Beijing' } // 无需提供所有嵌套属性
  }
};

// 类型安全的 Object.entries
type Entries<T> = {
  [K in keyof T]: [K, T[K]];
}[keyof T][];

function typedEntries<T extends object>(obj: T): Entries<T> {
  return Object.entries(obj) as Entries<T>;
}

// 使用示例
const config = { apiUrl: '/data', timeout: 5000 };
typedEntries(config).forEach(([key, value]) => {
  console.log(`${key}: ${value}`); // key 自动推断为 "apiUrl" | "timeout"
});

3. 复杂表单类型处理
// 动态表单字段类型
type FieldType = 'text' | 'number' | 'date';

type FormField<T extends FieldType> = {
  type: T;
  label: string;
  required?: boolean;
  // 根据字段类型约束额外配置
  config: T extends 'number' 
    ? { min?: number; max?: number } 
    : T extends 'date' 
    ? { minDate?: string; maxDate?: string }
    : {};
};

// 创建表单配置
const formConfig: FormField<FieldType>[] = [
  {
    type: 'text',
    label: '用户名',
    required: true,
    config: {}  // 文本类型无需额外配置
  },
  {
    type: 'number',
    label: '年龄',
    config: { min: 0, max: 120 } // 自动验证配置类型
  }
];

// 表单数据收集类型
type FormData<T extends FormField<FieldType>[]> = {
  [K in T[number]['label']]: 
    T[number] extends { type: 'number' } ? number : string;
};

// 使用示例
type MyFormData = FormData<typeof formConfig>;
const formData: MyFormData = {
  '用户名': 'Alice',
  '年龄': 25  // 自动推断为 number 类型
};

4. 类型安全的 HTTP 客户端封装
// 定义请求配置类型
type ApiConfig<TPayload, TResponse> = {
  url: string;
  method: 'GET' | 'POST' | 'PUT' | 'DELETE';
  data?: TPayload;                            // 请求载荷类型
  headers?: Record<string, string>;
  validateResponse?: (res: unknown) => TResponse; // 响应验证函数
};

// 泛型 HTTP 客户端
async function request<TPayload, TResponse>(
  config: ApiConfig<TPayload, TResponse>      // 输入输出类型关联
): Promise<TResponse> {
  try {
    const response = await fetch(config.url, {
      method: config.method,
      headers: config.headers,
      body: config.data ? JSON.stringify(config.data) : undefined
    });

    const jsonData = await response.json();
    
    // 执行自定义验证
    if (config.validateResponse) {
      return config.validateResponse(jsonData);
    }
    return jsonData as TResponse;             // 强制类型转换(慎用)
  } catch (error) {
    throw new Error(`Request failed: ${error}`);
  }
}

// 使用示例(带响应验证)
interface UserData {
  id: number;
  name: string;
}

const fetchUser = async (userId: number) => 
  request<never, UserData>({                  // GET 请求不需要 payload
    url: `/users/${userId}`,
    method: 'GET',
    validateResponse: (res) => {
      if (typeof res.id === 'number' && res.name) {
        return res as UserData;
      }
      throw new Error('Invalid user data');
    }
  });

5. 类型守卫高级模式
// 自定义类型守卫(判断数组元素类型)
function isStringArray(arr: unknown[]): arr is string[] {
  return arr.every(item => typeof item === 'string');
}

// 联合类型守卫
type ApiResponse = 
  | { status: 'success'; unknown }
  | { status: 'error'; message: string };

function handleResponse(response: ApiResponse) {
  if (response.status === 'success') {
    console.log('Data:', response.data);      // 自动收窄类型
  } else {
    console.error('Error:', response.message); 
  }
}

// 判别式联合 + 映射类型
type Animal = 
  | { type: 'dog'; barkVolume: number }
  | { type: 'cat'; purrDecibel: number };

function getAnimalSound(animal: Animal) {
  switch (animal.type) {
    case 'dog':
      return `Bark at ${animal.barkVolume}dB`; // 访问 dog 特有属性
    case 'cat':
      return `Purr at ${animal.purrDecibel}dB`; 
  }
}

代码注释设计原则
  1. 解释为什么(Why)
   // 使用 DeepPartial 处理嵌套表单更新场景
   type DeepPartial<T> = { ... };
  1. 强调类型安全点
   // 泛型约束确保 payload 类型与方法匹配
   function request<TPayload, TResponse>(...)
  1. 指出潜在陷阱
   // 注意:此处使用类型断言,需确保后端数据结构正确
   return jsonData as TResponse;
  1. 关联业务场景
   // 用户年龄范围限制(0-120岁实际业务需求)
   config: { min: 0, max: 120 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值