HarmonyOS APP《画伴梦工厂》开发第1篇:ArkTS 语言入门——从 TypeScript 到 ArkTS
第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装饰的组件会自动获得页面生命周期(aboutToAppear、aboutToDisappear、onPageShow、onPageHide)。@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
更多推荐



所有评论(0)