第1篇:ArkTS 语言入门——从 TypeScript 到 ArkTS

系列:鸿蒙 ArkTS 与 ArkUI 基础篇
难度:⭐ 入门
前置知识:TypeScript 基础


在这里插入图片描述

一、为什么是 ArkTS?

ArkTS 是华为为 HarmonyOS 应用开发量身定制的编程语言,基于 TypeScript 扩展而来。它保留了 TypeScript 的类型系统和现代 JavaScript 语法,同时引入了装饰器语法声明式 UI 能力,让开发者能用更少的代码写出更健壮的应用。

与标准 TypeScript 相比,ArkTS 有以下核心差异:

对比维度 TypeScript ArkTS
类型检查 编译时 + 运行时可选 强制编译时检查,禁止隐式 any
装饰器 实验性支持(experimentalDecorators) 一等公民,@Component/@State/@Builder 等
UI 渲染 无内置 UI 框架 声明式 UI 框架,与 build() 方法深度绑定
并发模型 Promise/async-await 支持 TaskPool/Worker 并发
动态特性 允许宽松模式 严格模式,禁止动态属性访问

二、ArkTS 的装饰器体系

ArkTS 最显著的特征是装饰器语法。在"画伴梦工厂"项目中,几乎每个文件都会用到装饰器。来看 Index.ets 中最核心的装饰器用法:

@Entry + @Component:声明页面组件

@Entry
@Component
struct Index {
  // 组件的状态和UI逻辑
  build() {
    // 声明式UI描述
  }
}
  • @Entry:标记当前组件是一个页面入口。被 @Entry 装饰的组件会自动获得页面生命周期(aboutToAppearaboutToDisappearonPageShowonPageHide)。
  • @Component:声明这是一个自定义组件。组件内部必须实现 build() 方法,描述 UI 结构。
  • struct:ArkTS 组件基于结构体(struct)定义,而非类(class)。这是因为 ArkTS 中组件是值类型,结构体的值语义更适合 UI 组件的不可变数据流。

与标准的 TypeScript 差异:TypeScript 中没有 @Component 这样的框架装饰器。ArkTS 将装饰器作为语言核心特性,而非实验性功能。

@State:响应式状态驱动

@Entry
@Component
struct Index {
  @StorageLink('mainBreakpoint') currentBreakpoint: string = 'md';
  @State private currentTab: number = 0;
  @State private secondaryPage: number = SECONDARY_NONE;
  @State private generationProgress: number = 68;
  @State private isPlaying: boolean = true;
  @State private chatInput: string = '';
  @State private chatMessages: ChatMessage[] = [
    { id: 1, role: 'assistant', text: '说出你想创作的角色和场景...', imageUri: '' }
  ];
  // ... 总共约30个 @State 变量
}

@State 是 ArkTS 响应式状态管理的核心。当 @State 变量的值发生变化时,依赖该变量的 UI 会自动重新渲染。项目中 Index.ets 使用了约 30 个 @State 变量来管理不同的 UI 状态——从当前 Tab 页、视频播放状态、聊天记录到画笔设置等。

@Builder:声明式 UI 复用

@Builder
private heroBanner() {
  Stack() {
    // 英雄区域背景和内容
  }
}

@Builder
private creationModeCard(mode: CreationMode) {
  Column() {
    Text(mode.title)
      .fontSize(18)
      .fontWeight(FontWeight.Bold)
    Text(mode.desc)
      .fontSize(14)
      .opacity(0.7)
    Progress({ value: mode.progress, type: ProgressType.Linear })
      .width('100%')
  }
}

项目中 Index.ets 定义了约 40 个 @Builder 方法,这是 ArkTS 推荐的 UI 片段复用方式。@Builder 可以接受参数,生成动态 UI 内容。


三、强类型接口与数据模型

ArkTS 要求所有数据结构必须明确定义类型,不允许隐式 any。项目中大量使用 interface 来定义数据模型:

// Index.ets 中的接口定义
interface Artwork {
  id: number;
  title: string;
  date: string;
  type: string;
  color: string;
  score: number;
  story: string;
}

interface ChatMessage {
  id: number;
  role: string;
  text: string;
  imageUri: string;
}

interface Metric {
  name: string;
  value: number;
}

interface CreationMode {
  title: string;
  desc: string;
  icon: string;
  color: string;
  progress: number;
}

在 ViewModel 层,还可以使用 Resource 类型来引用系统资源,这是 ArkTS 特有的一种类型安全方式:

// CatalogueItemData.ets
export class CatalogueItemData {
  id: number = 0;
  title: Resource = $r('app.string.responsive_layout');
  uri: string = '';
  params?: string;

  constructor(id: number, title: Resource, uri: string, params?: string) {
    this.id = id;
    this.title = title;
    this.uri = uri;
    this.params = params;
  }
}

与 TypeScript 的区别:TypeScript 中使用 Resource 类型须从模块导入,而 ArkTS 中 Resource 是内置类型,配合 $r() 函数使用——$r('app.string.responsive_layout') 会在编译时就检查资源是否存在。


四、常量与只读数组

ArkTS 中推荐使用 const 定义常量,使用 readonly 修饰不可变属性。项目中常见的模式:

// 模块级常量
const NAV_ITEMS: string[] = ['首页', '创作', '我的'];
const NAV_ICONS: string[] = ['⌂', '+', '♙'];
const SECONDARY_NONE: number = 0;
const SECONDARY_WORKS: number = 1;

// 数据常量(直接在模块作用域定义)
const WORKS: Artwork[] = [
  { id: 1, title: '蜡笔森林小恐龙', date: '2026-05-08', type: '幻想生物', color: '#AEEBFF', score: 92, story: '...' },
  { id: 5, title: '相亲相爱一家人', date: '2026-04-16', type: '角色伙伴', color: '#D8F7EA', score: 90, story: '...' },
  // ...
];

const METRICS: Metric[] = [
  { name: '想象力', value: 85 },
  { name: '色彩运用', value: 78 },
  { name: '构图能力', value: 72 },
  { name: '细节表达', value: 80 },
  { name: '创意独特性', value: 90 }
];

// 组件内的只读属性
private readonly pagePadding: number = 18;
private readonly brandPurple: string = '#7657F3';
private readonly softBackground: string = '#F7F5FF';

说明:这些数据常量定义在模块作用域中(而不是组件内部),属于模块级共享数据,可以被组件内的 build() 方法直接引用,不会触发不必要的组件刷新。这是 ArkTS 中常见的性能优化模式。


五、泛型与工具类

ArkTS 完全支持 TypeScript 的泛型语法。项目中有一个非常经典的泛型应用——BreakPointType<T>

// BreakpointSystem.ets
declare interface BreakPointTypeOption<T> extends Record<string, T | undefined> {
  sm?: T;
  md?: T;
  lg?: T;
  xl?: T;
  xxl?: T;
}

export class BreakPointType<T> {
  options: BreakPointTypeOption<T>;

  constructor(option: BreakPointTypeOption<T>) {
    this.options = option;
  }

  getValue(currentBreakPoint: string): T {
    return this.options[currentBreakPoint] as T;
  }
}

在 Index.ets 中,这个泛型工具被用于不同响应式断点下的取值:

// 根据断点返回不同数值
private pageEdge(): number {
  return new BreakPointType<number>({ sm: 12, md: 24, lg: 36, xl: 56 })
    .getValue(this.currentBreakpoint);
}

private panelWidth(): string {
  return new BreakPointType<string>({ sm: '90%', md: '86%', lg: '74%', xl: '64%' })
    .getValue(this.currentBreakpoint);
}

private heroHeight(): number {
  return new BreakPointType<number>({ sm: 420, md: 430, lg: 460, xl: 480 })
    .getValue(this.currentBreakpoint);
}

BreakPointType<T> 通过泛型参数 T 实现了类型安全的响应式取值——当断点为 md 时自动返回中间值,断点为 xl 时返回大屏值。且返回类型与传入类型一致(number 返回 number,string 返回 string),无需手动类型转换。


六、import 与模块系统

ArkTS 使用标准的 ES Module 语法导入模块。项目中展示了三种导入风格:

// 1. 导入系统 Kit 能力
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { mediaquery } from '@kit.ArkUI';
import { harmonyShare, systemShare } from '@kit.ShareKit';

// 2. 导入项目内部模块(通过 oh-package.json5 配置的别名)
import { BreakpointSystem, BreakPointType } from '@ohos/common';

// 3. 导入相对路径模块
import { AIGenerationService, GeneratedImage } from '../services/AIGenerationService';
import { VoiceRecognitionCallbacks, VoiceRecognitionService } from '../services/VoiceRecognitionService';

HarmonyOS Kit 的导入格式为 from '@kit.ModuleName',这是 ArkTS 特有的导入语法。项目内部模块则通过 oh-package.json5@ohos/common 别名引用。


七、类与封装

ArkTS 中的类(class)支持完整的访问修饰符和封装模式。以 Logger 为例:

// Logger.ets
export class Logger {
  private readonly prefix: string = 'testTag';
  private readonly domain: number = 0xFF00;
  private readonly format: string = '%{public}s, %{public}s';

  public debug(...args: string[]): void {
    hilog.debug(this.domain, this.prefix, this.format, args);
  }

  public info(...args: string[]): void {
    hilog.info(this.domain, this.prefix, this.format, args);
  }

  public warn(...args: string[]): void {
    hilog.warn(this.domain, this.prefix, this.format, args);
  }

  public error(...args: string[]): void {
    hilog.error(this.domain, this.prefix, this.format, args);
  }
}

再看 Service 层的静态方法类设计:

// AIGenerationService.ets 中的静态方法类(典型的 Service 设计模式)
export class AIGenerationService {
  static async generateImage(prompt: string): Promise<GeneratedImage> { /* ... */ }
  static async generateVideo(imageUrl: string, prompt: string): Promise<GeneratedVideo> { /* ... */ }
}

// PermissionGuard 同样是全静态方法的设计
export class PermissionGuard {
  static async requestCamera(): Promise<PermissionResult> { /* ... */ }
  static async requestAlbum(): Promise<PermissionResult> { /* ... */ }
  static async requestMicrophone(): Promise<PermissionResult> { /* ... */ }
}

工程实践:项目中 Service 层普遍采用全静态方法类的模式,不实例化,直接通过 AIGenerationService.generateImage() 调用。这种模式在 ArkTS 中非常常见,适合无状态的服务封装。


八、箭头函数与回调

ArkTS 支持箭头函数语法,项目中大量使用:

// 简洁的回调表达式
private readonly knockShareCallback =
  (target: harmonyShare.SharableTarget): void => {
    this.handleKnockShare(target).catch((error: Error) => {
      this.showNotice('碰一碰分享失败:' + this.getErrorMessage(error));
    });
  };

// 数组遍历与操作
private refreshWorks(): void {
  this.savedWorks = WorkRepository.list().reverse();
}

九、常见陷阱与注意事项

9.1 build() 方法中不能使用流程控制语句

ArkTS 的 build() 方法中,不能使用 if/else 条件语句(除三元运算符外)和 for 循环(除 ForEach/LazyForEach 外)。如果要条件渲染,必须使用三元表达式或 @Builder

build() {
  Column() {
    // ✅ 正确:使用三元表达式
    this.secondaryPage === SECONDARY_WORKS ?
      this.worksPage() : this.homePage()

    // ❌ 错误:不能在 build() 中使用 if
    // if (this.secondaryPage === SECONDARY_WORKS) { this.worksPage() }
  }
}

9.2 禁止隐式 any

// ❌ 错误:禁止隐式 any
// let data = getData();

// ✅ 正确:必须显式声明类型
// let data: Artwork[] = getData();
// 或
// let data = getData() as Artwork[];

9.3 回调中的 this 捕获

在 ArkTS 中,箭头函数自动捕获外部的 this,而普通函数则不会。项目中统一使用箭头函数:

// ✅ 正确:箭头函数自动捕获 this
setInterval(() => {
  this.animationFrame = (this.animationFrame + 1) % 6;
  this.generationProgress = Math.min(this.generationProgress + 2, 98);
}, 1200);

// ❌ 错误的做法:普通函数会丢失 this
// setInterval(function() {
//   this.animationFrame++;  // this 指向错误
// }, 1200);

十、总结

本文通过"画伴梦工厂"项目的真实代码,介绍了 ArkTS 的核心语法特性。从装饰器、强类型接口、泛型工具,到模块导入、类封装和箭头函数——ArkTS 在保持 TypeScript 熟悉的语法风格的同时,通过编译时强类型检查、声明式 UI 装饰器和严格的语法约束,为鸿蒙应用开发提供了更安全、更高效的编码体验。

下一篇预告:第 1.2 篇《ArkUI 声明式 UI 基础:组件、布局与样式》——我们将深入 Index.ets 中数十个 @Builder 构建的 UI 片段,学习 Column/Row/Stack 布局、Text/Image/Button 组件、以及鸿蒙特有的 $r 资源引用体系。


参考源码

  • products/default/src/main/ets/pages/Index.ets — 页面组件、状态管理、@Builder、响应式布局
  • common/src/main/ets/utils/Logger.ets — 类封装与 hilog 日志
  • common/src/main/ets/utils/BreakpointSystem.ets — 泛型工具类设计
  • products/default/src/main/ets/viewmodel/CatalogueItemData.ets — Resource 类型与数据模型
  • products/default/src/main/ets/components/CreationComponents.ets — @Link 与 @Component
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐