实现Concat

226 阅读2分钟

🤔 问题描述

将两个数组合并成一个新数组。这就像是在 JavaScript 中使用 Array.concat() 方法一样。

📝 举个例子

// 我们想要实现这样的效果:
type Result = Concat<[1], [2]>;  // 得到 [1, 2]

// 更多例子
type Example1 = Concat<[1, 2], [3, 4]>;  // 得到 [1, 2, 3, 4]
type Example2 = Concat<[], [1]>;         // 得到 [1]
type Example3 = Concat<['hello'], ['世界']>; // 得到 ['hello', '世界']

🔨 实现方案

type Concat<T extends readonly any[], U extends readonly any[]> = [...T, ...U]

🎓 知识点解析

  1. 扩展运算符(...)
  • TypeScript类型中,...的作用和JavaScript中一样
  • 可以展开数组中的所有元素
  1. extends 关键字
  • extends 用来限制类型
  • T extends readonly any[]表示T必须是一个数组类型
  1. readonly 修饰符
  • readonly表示数组是只读的
  • 使用readonly可以兼容更多类型的数组

🌰 使用示例

// 基础用法
type Result1 = Concat<[1], [2]>

// 合并多个元素
type Result2 = Concat<[1, 2], [3, 4]>

// 使用不同的类型
type Result3 = Concat<[1, '2'], [true]>

// 使用只读数组
type Result4 = Concat<readonly [1], readonly [2]>

🎯 加 readonly 和不加 readonly 的区别是什么

1. 类型兼容性

// 定义一个只读数组
const readArr = [1, 2, 3] as const;

// 不加 readonly 版本
type ConcatWithoutReadonly<T extends any[], U extends any[]> = [...T, ...U]
type Result1 = ConcatWithoutReadonly<typeof readArr, [4]> // ❌ 报错!

// 加 readonly 版本
type ConcatWithReadonly<T extends readonly any[], U extends readonly any[]> = [...T, ...U]
type Result2 = ConcatWithReadonly<typeof readArr, [4]>  // ✅ 正常工作

2. 为什么会这样

TypeScript 的类型系统中:

  • readonly array不能赋值给array
  • 但是array可以赋值给readonly array

就像这样:

type Test1 = readonly any[] extends any[] ? true : false // false
type Test2 = any[] extends readonly any[] ? true : false // true

3. 示例

// 场景1:普通数组
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

// 场景2:const 断言创建的只读数组
const arr3 = [1, 2, 3] as const;
const arr4 = [4, 5, 6] as const;

// 不加 readonly 的版本
type NormalConcat<T extends any[], U extends any[]> = [...T, ...U];
type Test1 = NormalConcat<typeof arr1, typeof arr2>;  // ✅ 正常
type Test2 = NormalConcat<typeof arr3, typeof arr4>;  // ❌ 报错

// 加 readonly 的版本
type ReadonlyConcat<T extends readonly any[], U extends readonly any[]> = [...T, ...U];
type Test3 = ReadonlyConcat<typeof arr1, typeof arr2>;  // ✅ 正常
type Test4 = ReadonlyConcat<typeof arr3, typeof arr4>;  // ✅ 正常

📝 实践建议

✅ 推荐使用 readonly 版本因为:

  1. 更好的类型兼容性。
  2. 可以处理所有数组类型。
  3. 支持as const断言的数组。

❌ 不加 readonly 的限制:

  1. 不能处理只读数组。
  2. 不能处理as const断言的数组。
  3. 类型兼容性较差。