适用版本 :HarmonyOS 6.1(API 12)及以上
验证环境 :Pura 90 Pro 模拟器(HarmonyOS 6.1.1,API 24)
关键概念:泛型类、泛型函数、类型参数约束、不可变数组操作
前言
泛型是让一套逻辑适配多种类型的机制。ArkTS 支持 TypeScript 风格的泛型语法,但有几处严格模式限制需要注意------本文用三个典型例子覆盖完整用法:泛型类(栈结构)、泛型对(Pair)、泛型函数(findMax / reverseArray)。
一、泛型类:MyStack<T>
为什么不叫 Stack<T>?
ArkTS 内置了 Stack 类,直接命名会导致符号冲突。实际项目中自定义容器类应避免与内置类重名。
typescript
class MyStack<T> {
private items: T[] = []
push(item: T): void {
// ArkTS 严格模式禁止 spread:不能 [...this.items, item]
// 必须手动循环重建数组
const next: T[] = []
for (let i = 0; i < this.items.length; i++) {
next.push(this.items[i])
}
next.push(item)
this.items = next
}
pop(): T | null {
if (this.items.length === 0) { return null }
const next: T[] = []
for (let i = 0; i < this.items.length - 1; i++) {
next.push(this.items[i])
}
const top = this.items[this.items.length - 1]
this.items = next
return top
}
peek(): T | null {
if (this.items.length === 0) { return null }
return this.items[this.items.length - 1]
}
isEmpty(): boolean { return this.items.length === 0 }
size(): number { return this.items.length }
toArray(): T[] {
const copy: T[] = []
for (let i = 0; i < this.items.length; i++) {
copy.push(this.items[i])
}
return copy
}
}
ArkTS 严格模式关键限制 :不支持扩展运算符 ... 操作数组(arkts-no-spread)。push、pop 都必须手动循环重建,这同时也满足不可变数据原则------每次操作返回新数组,不修改原数组。
二、泛型对:Pair<A, B>
封装两种不同类型的值,支持类型安全的 swap():
typescript
class Pair<A, B> {
first: A
second: B
constructor(first: A, second: B) {
this.first = first
this.second = second
}
// swap 返回新 Pair,类型参数交换
swap(): Pair<B, A> {
return new Pair<B, A>(this.second, this.first)
}
toString(): string {
return `(${this.first}, ${this.second})`
}
}
// 使用
const p = new Pair<string, number>('ArkTS', 12)
console.log(p.toString()) // (ArkTS, 12)
console.log(p.swap().toString()) // (12, ArkTS)
swap() 的返回类型 Pair<B, A> 利用泛型参数交换实现了编译期类型安全------交换后的 first 是 B 类型,second 是 A 类型,无需任何运行时类型检查。
三、泛型函数:findMax 与 reverseArray
ArkTS 严格模式不支持 extends 泛型约束(T extends Comparable),泛型函数的类型参数通常用于容器操作或委托比较:
typescript
// 数字数组最大值(直接用 number,避免 extends 约束限制)
function findMax(arr: number[]): number | null {
if (arr.length === 0) { return null }
let maxVal = arr[0]
for (let i = 1; i < arr.length; i++) {
if (arr[i] > maxVal) { maxVal = arr[i] }
}
return maxVal
}
// 反转任意类型数组(T 不需要比较能力,只需能存储)
function reverseArray<T>(arr: T[]): T[] {
const result: T[] = []
for (let i = arr.length - 1; i >= 0; i--) {
result.push(arr[i])
}
return result
}
// 使用
const nums: number[] = [42, 7, 98, 15, 63, 31]
findMax(nums) // 98
reverseArray(nums) // [31, 63, 15, 98, 7, 42]
reverseArray(['a', 'b', 'c']) // ['c', 'b', 'a']
reverseArray<T> 对任意类型数组都能复用同一逻辑,这是泛型的核心价值------一次编写,多类型复用。
@State 与泛型类的配合
泛型类实例作为 @State 的问题:@State 只能追踪值类型(基础类型、class 实例)的变化,无法追踪内部属性变更 。解决方案是将快照同步为 @State 数组:
typescript
// 私有持久化实例(不是 @State)
private numStack: MyStack<number> = new MyStack<number>()
// @State 快照,驱动 UI 刷新
@State stackSnapshot: number[] = []
// 每次 push/pop 后同步快照
private syncSnapshot(): void {
const arr = this.numStack.toArray()
const next: number[] = []
for (let i = 0; i < arr.length; i++) { next.push(arr[i]) }
this.stackSnapshot = next // 赋值触发 @State 刷新
}
这种"持久化实例 + @State 快照"模式是处理复杂数据结构与 UI 响应式绑定的标准方式。
模拟器运行截图
初始状态
栈为空,三个操作区(MyStack、Pair、泛型函数)均处于等待状态。

执行完成
push(1)、push(2),peek() 确认栈顶为 2;Pair<string,number> 构造与 swap();findMax 和 reverseArray 均返回正确结果。

实测结果:
| 操作 | 输入 | 结果 |
|---|---|---|
| push(1), push(2) | MyStack | 栈大小 2,peek() = 2 |
| Pair<string,number> | ('ArkTS', 12) | (ArkTS, 12),swap() → (12, ArkTS) |
| findMax | 42, 7, 98, 15, 63, 31 | 98 |
| reverseArray | 同上 | 31, 63, 15, 98, 7, 42 |
常见问题
Q:ArkTS 支持 T extends SomeInterface 这样的约束吗?
A:ArkTS 严格模式对泛型约束支持有限。T extends object 可以工作,但 T extends { compareTo(other: T): number } 这类结构化约束可能遇到编译错误。推荐改用函数参数传入比较器:function sort<T>(arr: T[], compare: (a: T, b: T) => number): T[]。
Q:泛型类可以加 @Sendable 吗?
A:不能直接对泛型类加 @Sendable。@Sendable 要求所有属性类型都是 Sendable 类型(number/string/boolean 或 collections.Array),而泛型 T 无法在编译期保证是 Sendable 类型。
Q:MyStack<T> 的 push 为何不直接 this.items.push(item)?
A:直接修改 this.items(可变操作)在 ArkTS 严格模式下通常没有编译错误,但 @State 不会感知到数组内部元素的增加------@State 追踪的是引用变化,不是内容变化。每次重建新数组并赋值,才能保证 UI 响应式刷新。