# TypeScript 严格规范

## 类型定义位置

```
src/types/
├── api.d.ts      # ApiResponse, PageParams, etc.
├── user.d.ts     # User domain types
├── order.d.ts    # Order domain types
└── common.d.ts   # Shared utilities
```

## 禁止 `any` 的替代方案

| 场景 | 错误 | 正确 |
|------|------|------|
| 未知对象 | `any` | `Record<string, unknown>` |
| 动态数组 | `any[]` | `unknown[]` + type guard |
| 回调函数 | `(x: any) => any` | 泛型 `<T>(x: T) => T` |
| 第三方库缺失类型 | `any` | 创建 `.d.ts` 声明文件 |

## Props 与 Emits 类型化

```typescript
// Props
interface Props {
  user: User
  mode?: 'view' | 'edit'
  onSave?: (data: User) => void
}

const props = withDefaults(defineProps<Props>(), {
  mode: 'view',
})

// Emits
interface Emits {
  (e: 'update', value: User): void
  (e: 'cancel'): void
}

const emit = defineEmits<Emits>()
```

## 泛型组合式函数

```typescript
// composables/useFetch.ts
export function useFetch<T>(
  fetcher: () => Promise<T>,
  options?: { immediate?: boolean }
) {
  const data = ref<T | null>(null) as Ref<T | null>
  const loading = ref(false)
  const error = ref<Error | null>(null)

  async function execute() {
    loading.value = true
    error.value = null
    try {
      data.value = await fetcher()
    } catch (e) {
      error.value = e instanceof Error ? e : new Error(String(e))
    } finally {
      loading.value = false
    }
  }

  if (options?.immediate !== false) {
    onMounted(execute)
  }

  return { data, loading, error, execute }
}
```

## 类型守卫

```typescript
function isUser(obj: unknown): obj is User {
  return (
    typeof obj === 'object' &&
    obj !== null &&
    'id' in obj &&
    'name' in obj
  )
}

// 使用
const data: unknown = await fetchData()
if (isUser(data)) {
  console.log(data.name) // TypeScript 知道这是 User
}
```

## 联合类型与字面量类型

```typescript
// 状态枚举替代方案
type UserStatus = 'active' | 'disabled' | 'pending'

// 带类型的事件处理
type TableAction =
  | { type: 'edit'; payload: User }
  | { type: 'delete'; payload: string }
  | { type: 'view'; payload: User }

function handleAction(action: TableAction) {
  switch (action.type) {
    case 'edit':
      openEditDialog(action.payload) // payload 是 User
      break
    case 'delete':
      confirmDelete(action.payload) // payload 是 string (id)
      break
  }
}
```

## 工具类型使用

```typescript
// Partial - 所有属性可选
type UpdateUserDto = Partial<User>

// Pick - 选择部分属性
type UserPreview = Pick<User, 'id' | 'name' | 'avatar'>

// Omit - 排除部分属性
type CreateUserDto = Omit<User, 'id' | 'createdAt' | 'updatedAt'>

// Required - 所有属性必填
type CompleteUser = Required<User>

// Record - 键值映射
type UserMap = Record<string, User>

// 自定义工具类型
type Nullable<T> = T | null
type AsyncReturnType<T extends (...args: any) => Promise<any>> =
  T extends (...args: any) => Promise<infer R> ? R : never
```
