【HarmonyOS实战】 ArkTS语言基础:从TypeScript到鸿蒙的第一步
很多人第一次看 HarmonyOS 的代码,发现它长得挺像 TypeScript,又好像多了些奇怪的东西——@Component@Statebuild()方法……这些是啥?ArkTS是华为基于 TypeScript 4.x 扩展的编程语言。TypeScript 能写的,ArkTS 基本都能写;ArkTS 还额外提供了一套用于构建 UI 的扩展语法。本篇我们从项目源码出发,把 ArkTS 的基础语法
前言
很多人第一次看 HarmonyOS 的代码,发现它长得挺像 TypeScript,又好像多了些奇怪的东西——@Component、@State、build() 方法……这些是啥?
ArkTS 是华为基于 TypeScript 4.x 扩展的编程语言。TypeScript 能写的,ArkTS 基本都能写;ArkTS 还额外提供了一套用于构建 UI 的扩展语法。本篇我们从项目源码出发,把 ArkTS 的基础语法捋一遍,让你读懂后续所有代码。
项目预览


一、ArkTS 的核心基础
1.1 变量声明
ArkTS 使用 let(变量)和 const(常量),这和 TypeScript / JavaScript 完全一样:
let count: number = 0; // 数字类型
const name: string = 'Hello'; // 字符串常量
let isVisible: boolean = true; // 布尔类型
let items: string[] = []; // 字符串数组
提示:ArkTS 要求强制类型标注,不能像 JS 那样写
let x = 1就不管类型了。变量声明时最好明确写出类型,养成好习惯。
1.2 函数定义
// 普通函数
function add(a: number, b: number): number {
return a + b;
}
// 箭头函数
const greet = (name: string): string => {
return `Hello, ${name}`;
};
// async 异步函数(项目中大量使用)
async function fetchData(): Promise<string> {
let result = await someAsyncOperation();
return result;
}
项目中的 MapUtil.ets 里大量使用了 async/await,比如获取当前位置:
// entry/src/main/ets/utils/MapUtil.ets
async getMyLocation(): Promise<geoLocationManager.Location> {
let location: geoLocationManager.Location = await geoLocationManager.getCurrentLocation();
return location;
}
async 表示这个方法是异步的,await 等待异步操作完成,返回类型是 Promise<Location>。
二、interface 和 class
2.1 interface 接口
接口定义数据的"形状",规定一个对象应该有哪些字段:
// entry/src/main/ets/model/StationData.ets
export interface StationData {
image: ResourceStr; // 图片资源(可以是字符串或资源引用)
id: string; // 唯一标识
name: string; // 加油站名称
addr: string; // 地址
latitude: number; // 纬度
longitude: number; // 经度
}
这是项目里的加油站数据模型。定义 interface 之后,我们创建的每个加油站数据对象都必须包含这些字段,少了会报错。
// 正确的使用方式
let station: StationData = {
image: $r('app.media.image1'),
id: '1',
name: '中国石化加油站(AA站)',
addr: 'N市J区XX大街587号',
latitude: 31.937176963332842,
longitude: 118.86018812656404,
};
2.2 class 类
类是对功能的封装。项目中的工具类都用 class 实现:
// entry/src/main/ets/utils/Logger.ets
export class Logger {
private static domain: number = 0x0000; // 私有静态属性
private static prefix: string = 'NearByGasStationDemo';
static info(...args: string[]): void { // 静态方法,直接 Logger.info() 调用
hilog.info(Logger.domain, Logger.prefix, Logger.format, args);
}
static error(...args: string[]): void {
hilog.error(Logger.domain, Logger.prefix, Logger.format, args);
}
}
static 的意思:不需要实例化就能调用,直接 Logger.info('消息') 用。
private 的意思:只在类内部能访问,外部访问不到。
// 外部使用方式
Logger.info('testTag', '初始化成功');
Logger.error('testTag', `出错了: ${err.message}`);
2.3 @Observed 装饰的类
这是 ArkTS 特有的扩展。给一个类加上 @Observed,表示这个类的实例被 UI 框架"观察",它的属性变化会触发 UI 刷新:
// entry/src/main/ets/utils/MapUtil.ets
@Observed
export class MapUtil {
// ... 方法实现
}
提示:
@Observed常和@ObjectLink装饰器配合使用,实现深层数据的响应式更新。本项目中MapUtil使用@Observed主要是为了标识这是一个可观察对象,为后续状态联动做准备。
三、export 和 import
ArkTS 使用 ES Module 的模块系统,跟 TypeScript/JavaScript 完全一样。
3.1 导出
// 导出 interface
export interface StationData { ... }
// 导出常量
export const STATION_LIST: StationData[] = [ ... ];
// 导出 class
export class Logger { ... }
// 默认导出(一个文件只能有一个)
export default class EntryAbility extends UIAbility { ... }
3.2 导入
// 从相对路径导入
import { Constants } from '../common/Constants';
import { Logger } from '../utils/Logger';
import { STATION_LIST, StationData } from '../model/StationData';
// 从 Kit 包导入(HarmonyOS 系统能力)
import { map, mapCommon, MapComponent } from '@kit.MapKit';
import { geoLocationManager } from '@kit.LocationKit';
import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';
@kit.MapKit 这样的 @kit.xxx 是 HarmonyOS 提供的系统 Kit 包,不需要手动安装,直接 import 就能用。
四、ArkTS 特有扩展:装饰器
这是 ArkTS 和普通 TypeScript 差别最大的地方。装饰器以 @ 开头,用来给类、方法、属性加上"标签",告诉框架这个东西是干什么用的。
4.1 组件相关装饰器
| 装饰器 | 作用 |
|---|---|
@Entry |
标记一个组件为页面入口(每个页面有且只有一个) |
@Component |
标记为 ArkUI 组件(可复用的 UI 单元) |
@Builder |
标记为构建函数(可以在 build() 里调用的 UI 片段) |
// MainPage.ets
@Entry // 这是页面入口
@Component // 这是一个组件
struct MainPage {
build() {
// UI 构建逻辑
}
}
提示:注意是
struct(结构体)而不是class。在 ArkTS 中,UI 组件必须用struct定义,不能用class。
4.2 状态管理装饰器
| 装饰器 | 作用 |
|---|---|
@State |
组件内部状态,变化时触发 UI 刷新 |
@StorageProp |
从 AppStorage 读取值,AppStorage 变化时同步更新 |
@Prop |
从父组件接收数据(单向同步) |
@Link |
从父组件接收数据(双向同步) |
项目中最常见的用法:
// GasStationPage.ets
@Component
struct GasStationPage {
@State stationInfoList: StationData[] = []; // 内部状态:加油站列表
@State latitude: number = 0; // 内部状态:当前纬度
@State isShow: boolean = false; // 内部状态:是否显示底部弹窗
@StorageProp('bottomRectHeight') // 从全局存储读取导航栏高度
bottomRectHeight: number = 0;
@StorageProp('topRectHeight') // 从全局存储读取状态栏高度
topRectHeight: number = 0;
}
@State 是最重要的:当 @State 修饰的变量值发生变化时,组件会自动重新渲染,不需要手动调用任何刷新方法。这是响应式编程的核心。
五、可选类型与非空断言
5.1 可选类型(?)
在 ArkTS 中,? 表示这个属性或参数是可选的:
// 可选属性
private mapOptions?: mapCommon.MapOptions; // 可能是 undefined
// 可选参数
moveToGasStation(latitude?: number, longitude?: number): void {
if (latitude && longitude) { // 需要先检查是否有值
// ...
}
}
5.2 非空断言(!)
当你确定某个值不是 null/undefined,但 TypeScript 不知道,可以用 ! 告诉编译器"相信我,它不为空":
// MapUtil.ets
mapUtil.moveToCurrentPosition(
this.latitude,
this.longitude,
this.mapController as map.MapComponentController // 类型断言
);
as 是类型断言,相当于"我确定它是这个类型"。
六、展开运算符与数组操作
项目中用到了一些 TypeScript 常见的数组操作:
// forEach 遍历
this.stationInfoList.forEach(async (stationItem: StationData) => {
await mapUtil.addMapMaker(
stationItem.latitude,
stationItem.longitude,
this.mapController as map.MapComponentController
);
});
forEach 接收一个回调函数,对数组每个元素执行操作。注意这里的回调是 async 的,意味着每次添加标记都是异步操作。
总结
这篇文章覆盖了项目中用到的所有 ArkTS 基础语法:
- 变量与函数:和 TypeScript 基本一致
- interface:定义数据模型的形状
- class:封装工具方法,
static方法直接调用 - export/import:模块化管理代码
- 装饰器:ArkTS 特有,
@Entry、@Component、@State是最常用的三个 - 可选类型与非空断言:处理可能为空的情况
下一篇我们开始讲 ArkUI 声明式 UI,搞清楚 Column、Row、Text、Image 这些组件是怎么拼在一起构建界面的。
更多推荐
所有评论(0)