← 返回导航

数组类型推断的坑

踩坑记录

场景说明

TS 对数组字面量的类型推断有时会出乎意料:const arr = [1, 2] 被推断为 number[] 而不是 [number, number],空数组 [] 被推断为 never[]。这些推断在 useState 初始化、函数返回数组、常量枚举等场景中经常引发类型错误。

完整代码


      
// 数组类型推断的常见坑

// 坑一:字面量数组推断为宽泛类型
const arr1 = [1, 2, 3];            // 推断为 number[]
const arr2 = ['a', 'b'];           // 推断为 string[]
const arr3 = [1, 'a'];            // 推断为 (string | number)[]

// 如果你期望的是固定长度元组,需要 as const 或显式声明
const tuple1 = [1, 2] as const;       // 推断为 readonly [1, 2]
const tuple2: [number, number] = [1, 2];  // 显式元组类型

// 坑二:空数组推断为 never[]
const empty = [];                  // 推断为 never[]
// empty.push(1);  // 错误!never[] 不能 push number

// 解决:显式声明类型
const emptyNum: number[] = [];
const emptyStr: string[] = [];

// 坑三:React useState 初始值类型推断
// const [list, setList] = useState([]);  // list 推断为 never[]
// setList([1, 2, 3]);  // 错误!不能将 number[] 赋值给 never[]

// 解决:给 useState 加泛型
// const [list, setList] = useState<number[]>([]);

// 坑四:函数返回数组的类型推断
function getPair() {
  return [1, 2];  // 推断为 number[],不是 [number, number]
}
const pair = getPair();
// pair[0] 是 number,但 pair 可以 push(3),不是元组

// 解决:显式声明返回类型
function getPairFixed(): [number, number] {
  return [1, 2];
}

// 坑五:as const 让数组变只读元组
const roles = ['admin', 'user', 'guest'] as const;
// 推断为 readonly ["admin", "user", "guest"]
type Role = typeof roles[number];  // "admin" | "user" | "guest"
// roles.push('manager');  // 错误!只读数组不能修改

关键点解析

使用示例与类型推导


      
// 最佳实践:数组推断的各种正确姿势

// 1. 普通数组 -- 不需要特殊处理
const nums: number[] = [1, 2, 3];

// 2. 固定元组 -- 显式声明
const point: [number, number] = [10, 20];

// 3. 字面量枚举 -- as const
const colors = ['red', 'green', 'blue'] as const;
type Color = typeof colors[number]; // "red" | "green" | "blue"

// 4. 空数组初始化 -- 显式类型
const items: string[] = [];
items.push('hello');  // OK

// 5. 混合类型数组 -- 联合类型
const mixed: (string | number)[] = [1, 'two', 3];

// 6. React useState 正确写法
// const [users, setUsers] = useState<User[]>([]);
// const [status, setStatus] = useState<'idle' | 'loading' | 'error'>('idle');
在 Playground 中尝试