在这里插入图片描述

ArkTS泛型

泛型(Generics) 是现代强类型语言中用于编写高复用性、高安全性代码的核心机制。它允许开发者在定义类、接口或方法时不指定具体类型,而使用“类型占位符”(如 TU),等到实际使用时再传入具体的类型参数。

这样做的核心优势在于:

  • 编译期类型检查:避免运行时因类型错误导致的崩溃;
  • 消除冗余类型转换:无需频繁使用 as 或强制断言;
  • 提升代码可维护性:一套逻辑适配多种数据类型。

下面从泛型类、泛型约束到泛型方法,逐步展开说明。


泛型类

泛型类是指在类定义中包含一个或多个类型参数的类。这些参数在实例化时被具体类型替换,从而生成类型安全的对象。

以成绩管理为例,我们定义一个通用的 Grade<T> 类:

class Grade<T> {
  private value: T;

  constructor(value: T) {
    this.value = value;
  }

  getValue(): T {
    return this.value;
  }
}

在这里插入图片描述

当我们分别传入 numberstring 类型的数据时,编译器会自动推断并确保返回值类型与输入一致:

let numGrade = new Grade<number>(95);
let strGrade = new Grade<string>("A");

console.log(numGrade.getValue()); // 类型为 number
console.log(strGrade.getValue()); // 类型为 string

在这里插入图片描述

优势体现:无需为每种成绩类型(数字、字母、等级)重复编写几乎相同的类,极大提升了代码复用率。


泛型约束

虽然泛型提供了灵活性,但有时我们需要限制类型参数的范围,以确保其具备某些特定属性或方法。这就是泛型约束(Generic Constraints) 的作用。

通过 extends 关键字,我们可以要求泛型参数必须实现某个接口或继承某个类。

以下示例中,我们定义了一个 BasicScore 接口作为约束条件:

// 定义基础成绩接口约束
interface BasicScore {
  value: number | string;
  isValid(): boolean;
}

export class Grade<T extends BasicScore> {
  private _score: T;

  constructor(score: T) {
    this._score = score;
  }

  // 应用泛型约束的方法
  getFormattedScore(): string {
    if (this._score.isValid()) {
      return `成绩有效: ${this._score.value}`;
    }
    return "无效成绩";
  }
}

// 实现约束接口的具体类
export class MathScore implements BasicScore {
  value: number;

  constructor(value: number) {
    this.value = value;
  }

  isValid(): boolean {
    return this.value >= 0 && this.value <= 100;
  }
}

由于 Grade<T> 要求 T 必须实现 BasicScore,因此只有符合该结构的对象才能被传入。这保证了 getFormattedScore() 方法中可以安全调用 isValid() 和访问 value

🔒 安全边界:泛型约束在保持泛型灵活性的同时,建立了类型安全的“契约”,防止非法类型传入。

在这里插入图片描述


泛型方法

泛型方法是指在方法级别使用类型参数,而不依赖于所在类是否为泛型类。它特别适合用于工具函数或独立操作。

例如,一个简单的泛型方法:

// 泛型方法
function getGrade<T>(grade: T): T {
  return grade;
}

调用时可显式指定类型,也可由编译器自动推断:

let result1 = getGrade<string>("A");
let result2 = getGrade(95); // 自动推断为 number

🌐 适用场景:数组工具(如 find, map)、数据转换、缓存读取等需要“透传类型”的场合。

在这里插入图片描述


空值安全

在 JavaScript 中,nullundefined 是常见的运行时错误来源(如 “Cannot read property of undefined”)。ArkTS 通过一系列空值安全特性,帮助开发者在编译阶段就规避此类风险。

联合类型

联合类型(Union Types)使用 | 符号组合多个可能的类型,明确声明变量的合法取值范围,强制开发者处理所有可能性。

let score: number | string = 95;           // 允许数字或字符串
let nullableValue: string | null = null;   // 显式声明可能为空

💡 设计意图:通过类型系统表达“不确定性”,避免隐式假设。例如,若未声明 | null,则 nullableValue = null 会直接报错。

  • 特性说明:通过 | 符号组合类型,强制开发者在使用前进行类型判断(如 typeof!== null 等)。

非空断言运算符 (!)

当开发者确定某个值在运行时一定不为 nullundefined,但编译器无法推断时,可使用 非空断言运算符 ! 强制跳过空值检查。

class Test {
    v: number | null = 1;
}
let obj = new Test();
let result = obj.v! + 5;  // 告诉编译器:v 肯定有值

⚠️ 严重警告! 不做任何运行时检查!如果实际值为空,程序将抛出异常。仅在 100% 确保非空时使用,如生命周期钩子中已初始化的字段。

  • 注意事项:需开发者自行确保实际值不为空,滥用可能导致运行时异常。

空值合并运算符 (??)

空值合并运算符 ?? 用于在值为 nullundefined 时提供默认值,不会将 0false'' 视为空(区别于 ||)。

let configValue: number | null = null;
let finalValue = configValue ?? 3000;  // 仅当 configValue 为 null/undefined 时取 3000

典型对比

  • value || defaultValue:当 value 为 falsy(如 0, '', false)时也会使用默认值;
  • value ?? defaultValue:仅在 value == null(即 nullundefined)时使用默认值。
  • 等效逻辑:value = (input != null) ? input : defaultValue

可选链操作符 (?.)

可选链操作符 ?. 允许安全地访问嵌套对象的属性、方法或数组元素。如果链中任意一级为 nullundefined,整个表达式会短路并返回 undefined,而不会抛出错误。

// 可选链操作符(?.)
class Person {
    address?: City;
}
let user = new Person();
user.address?.show(); // 若 address 为 undefined,则不执行 show()
console.log('可选链操作符', user.address?.show()); // 安全调用

配套定义:

class City {
  show(){
    console.log('可选链操作符:Hello');
  }
}   

在这里插入图片描述

🌐 典型场景:处理来自网络 API 的深层嵌套 JSON 数据时,避免因某一层缺失而导致程序崩溃。

  • 典型场景:处理API返回的深层嵌套数据结构时避免undefined is not an object错误。

最佳实践建议

ArkTS 的空值安全体系鼓励开发者显式处理不确定性。建议按以下优先级选择方案:

  1. 首选联合类型(如 T | null
    → 明确表达“可能为空”的语义,迫使调用方处理分支逻辑。

  2. 需要默认值时使用空值合并 ??
    → 安全且语义清晰,避免误判 0false 为无效值。

  3. 访问不确定属性时采用可选链 ?.
    → 防止因中间节点缺失导致的运行时错误。

  4. 仅在确保非空时谨慎使用非空断言 !
    → 作为最后手段,需配合充分的逻辑验证或注释说明。


通过泛型与空值安全机制的结合,ArkTS 在保持 TypeScript 开发体验的同时,显著提升了代码的健壮性与可预测性。这些特性不仅是语法糖,更是构建高质量鸿蒙应用的重要基石。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐