Skip to content

ArkTS 语言基础

ArkTS 是华为基于 TypeScript 扩展而来的声明式编程语言,专为 HarmonyOS 应用开发设计。它在保持 TypeScript 语法特性的基础上,增加了声明式 UI、状态管理和严格的类型约束,以确保更好的运行时性能和类型安全。

与 TypeScript 的区别

ArkTS 在 TypeScript 基础上增加了一些限制,以确保更好的性能和类型安全:

特性TypeScriptArkTS
any 类型允许禁止
动态属性添加允许禁止
eval / new Function允许禁止
声明式 UI不支持支持
状态管理装饰器不支持支持
并发模型单线程TaskPool/Worker
typescript
// ❌ 错误(ArkTS 不允许)
let a: any = 1
a = 'x'

const obj = {}
obj.name = '张三'

// ✅ 正确
let a: number = 1

class Person {
  name: string = ''
}
const obj: Person = { name: '张三' }

提示

ArkTS 的严格类型检查在编译阶段就能发现大部分错误,建议始终显式声明类型。

基本数据类型

ArkTS 支持 TypeScript 的所有基本数据类型:

number

数字类型,包括整数和浮点数:

typescript
let integer: number = 42
let floating: number = 3.14
let hex: number = 0xff      // 十六进制
let binary: number = 0b1010 // 二进制
let octal: number = 0o744   // 八进制
let infinity: number = Infinity
let notANumber: number = NaN

string

字符串类型,支持单引号、双引号和模板字符串:

typescript
let single: string = 'Hello'
let double: string = "World"
let name: string = 'ArkTS'
let greeting: string = `Welcome to ${name}!`
let multiLine: string = `
  第一行
  第二行
  第三行
`

boolean

布尔类型:

typescript
let isDone: boolean = false
let isValid: boolean = true

null 和 undefined

typescript
let n: null = null
let u: undefined = undefined

// 联合类型使用
let value: string | null = null
value = 'hello'

symbol

Symbol 类型用于创建唯一的标识符:

typescript
let sym1: symbol = Symbol('key')
let sym2: symbol = Symbol('key')

console.info(sym1 === sym2) // false,每个 Symbol 都是唯一的

// 用作对象属性键
const id: symbol = Symbol('id')

bigint

BigInt 类型用于表示任意大的整数:

typescript
let big: bigint = 9007199254740991n
let another: bigint = BigInt(123)

// 大数运算
let sum: bigint = big + 1n

void

void 表示没有返回值,通常用于函数:

typescript
function logMessage(msg: string): void {
  console.info(msg)
}

联合类型

联合类型表示一个值可以是多种类型之一:

typescript
type Status = 'idle' | 'loading' | 'done'
let currentStatus: Status = 'idle'

// 数字或字符串
type ID = number | string
let userId: ID = 1001
userId = 'U1001'

数组和元组

Array 数组

数组用于存储有序数据集合,提供两种声明方式:

typescript
// 方式一:类型后缀
let numbers: number[] = [1, 2, 3]
let strings: string[] = ['a', 'b', 'c']

// 方式二:泛型语法
let arr1: Array<number> = [1, 2, 3]
let arr2: Array<string> = ['a', 'b']

// 多维数组
let matrix: number[][] = [[1, 2], [3, 4]]

// 数组方法
let nums: number[] = [1, 2, 3]
nums.push(4)        // 添加元素
nums.pop()          // 移除最后一个
nums.shift()        // 移除第一个
nums.unshift(0)     // 在开头添加
nums.splice(1, 1)   // 删除指定位置
let sliced: number[] = nums.slice(0, 2) // 截取

ArrayList

ArkTS 提供了 @arkts.collections 中的 ArrayList:

typescript
import { collections } from '@kit.ArkTS'

let list: collections.ArrayList<number> = new collections.ArrayList()
list.add(1)
list.add(2)
list.add(3)
console.info(list.get(0)) // 1
console.info(list.size())   // 3

Set 集合

Set 存储唯一值:

typescript
let uniqueNums: Set<number> = new Set([1, 2, 2, 3])
console.info(uniqueNums.size) // 2

uniqueNums.add(4)
uniqueNums.delete(1)
uniqueNums.has(2) // true
uniqueNums.clear()

Map 映射

Map 存储键值对:

typescript
let userMap: Map<string, number> = new Map()
userMap.set('Alice', 25)
userMap.set('Bob', 30)

console.info(userMap.get('Alice')) // 25
console.info(userMap.has('Bob'))   // true
userMap.delete('Alice')
console.info(userMap.size)         // 1

// 遍历
for (let [key, value] of userMap) {
  console.info(`${key}: ${value}`)
}

元组 Tuple

元组表示固定长度、固定类型的数组:

typescript
// 定义元组类型
let person: [string, number] = ['张三', 25]

// 可选元素
let optionalTuple: [string, number?] = ['hello']
optionalTuple = ['hello', 42]

// 剩余元素
let restTuple: [string, ...number[]] = ['scores', 90, 85, 88]

// 只读元组
let readonlyTuple: readonly [string, number] = ['a', 1]
// readonlyTuple[0] = 'b' // ❌ 错误:无法修改

接口与类

接口 Interface

接口定义对象的结构契约:

typescript
// 基础接口
interface User {
  id: number
  name: string
  age?: number        // 可选属性
  readonly email: string // 只读属性
}

const user: User = {
  id: 1,
  name: '张三',
  email: 'zhangsan@example.com'
}

// 接口继承
interface Animal {
  name: string
}

interface Dog extends Animal {
  breed: string
}

const myDog: Dog = {
  name: '旺财',
  breed: '金毛'
}

// 接口定义函数类型
interface SearchFunc {
  (source: string, subString: string): boolean
}

let mySearch: SearchFunc = function(src: string, sub: string): boolean {
  return src.indexOf(sub) > -1
}

// 接口定义索引签名
interface StringArray {
  [index: number]: string
}

let myArray: StringArray = ['Bob', 'Fred']

类 Class

typescript
// 基础类
class Account {
  balance: number = 0

  deposit(amount: number): void {
    this.balance += amount
  }

  withdraw(amount: number): boolean {
    if (this.balance >= amount) {
      this.balance -= amount
      return true
    }
    return false
  }
}

const account = new Account()
account.deposit(100)
console.info('余额:', account.balance)

访问修饰符

typescript
class Person {
  public name: string = ''           // 公开(默认)
  private age: number = 0            // 私有
  protected id: string = ''          // 受保护
  readonly email: string = ''        // 只读

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }

  public getAge(): number {
    return this.age
  }

  private setAge(age: number): void {
    this.age = age
  }
}

class Employee extends Person {
  constructor(name: string, age: number, id: string) {
    super(name, age)
    this.id = id        // 可以访问 protected
    // this.age = age   // ❌ 错误:无法访问 private
  }
}

抽象类

typescript
abstract class Animal {
  abstract makeSound(): void  // 抽象方法

  move(): void {
    console.info('移动中...')
  }
}

class Dog extends Animal {
  makeSound(): void {
    console.info('汪汪!')
  }
}

// let animal = new Animal() // ❌ 错误:不能实例化抽象类
let dog = new Dog()
dog.makeSound()
dog.move()

接口实现

typescript
interface CanFly {
  fly(): void
}

interface CanSwim {
  swim(): void
}

// 实现多个接口
class Duck implements CanFly, CanSwim {
  fly(): void {
    console.info('鸭子在飞')
  }

  swim(): void {
    console.info('鸭子在游泳')
  }
}

函数

函数声明

typescript
// 命名函数
function add(a: number, b: number): number {
  return a + b
}

// 函数表达式
let multiply = function(a: number, b: number): number {
  return a * b
}

箭头函数

typescript
// 基本箭头函数
let square = (x: number): number => x * x

// 多行箭头函数
let greet = (name: string): string => {
  let prefix: string = 'Hello, '
  return prefix + name
}

// 无参数
let getRandom = (): number => Math.random()

// 多个参数
let concat = (a: string, b: string): string => a + b

默认参数

typescript
function greetUser(name: string, greeting: string = 'Hello'): string {
  return `${greeting}, ${name}!`
}

console.info(greetUser('张三'))        // Hello, 张三!
console.info(greetUser('李四', 'Hi'))  // Hi, 李四!

剩余参数

typescript
function sum(...numbers: number[]): number {
  return numbers.reduce((total, num) => total + num, 0)
}

console.info(sum(1, 2, 3, 4)) // 10

// 与其他参数结合
function greetEveryone(greeting: string, ...names: string[]): string {
  return `${greeting}, ${names.join(' 和 ')}!`
}

函数重载

typescript
// 重载签名
function process(input: string): string
function process(input: number): number
function process(input: boolean): boolean

// 实现签名
function process(input: string | number | boolean): string | number | boolean {
  if (typeof input === 'string') {
    return input.toUpperCase()
  } else if (typeof input === 'number') {
    return input * 2
  } else {
    return !input
  }
}

console.info(process('hello')) // HELLO
console.info(process(42))      // 84
console.info(process(true))    // false

函数类型

typescript
// 定义函数类型
type MathOperation = (a: number, b: number) => number

let add: MathOperation = (x, y) => x + y
let subtract: MathOperation = (x, y) => x - y

// 回调函数类型
function processArray(arr: number[], callback: (item: number) => void): void {
  for (let item of arr) {
    callback(item)
  }
}

processArray([1, 2, 3], (item) => {
  console.info(item)
})

泛型

泛型让函数、接口和类可以与多种类型一起工作,提供类型安全的同时保持灵活性。

泛型函数

typescript
function first<T>(arr: T[]): T | undefined {
  return arr[0]
}

const firstNum = first<number>([1, 2, 3])    // number | undefined
const firstStr = first<string>(['a', 'b'])   // string | undefined

// 泛型约束
interface HasLength {
  length: number
}

function logLength<T extends HasLength>(arg: T): T {
  console.info(arg.length)
  return arg
}

logLength('hello')     // 5
logLength([1, 2, 3])   // 3
// logLength(123)      // ❌ 错误:number 没有 length 属性

泛型接口

typescript
interface Response<T> {
  code: number
  data: T
  message: string
}

interface UserData {
  id: number
  name: string
}

const userResponse: Response<UserData> = {
  code: 200,
  data: { id: 1, name: '张三' },
  message: 'success'
}

// 泛型接口与函数
interface GenericIdentityFn<T> {
  (arg: T): T
}

let identity: GenericIdentityFn<number> = (x) => x

泛型类

typescript
class GenericNumber<T> {
  zeroValue: T
  add: (x: T, y: T) => T

  constructor(zeroValue: T, addFn: (x: T, y: T) => T) {
    this.zeroValue = zeroValue
    this.add = addFn
  }
}

let myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y)
console.info(myGenericNumber.add(5, 3)) // 8

// 泛型约束示例
class Repository<T extends { id: number }> {
  private items: T[] = []

  add(item: T): void {
    this.items.push(item)
  }

  findById(id: number): T | undefined {
    return this.items.find(item => item.id === id)
  }
}

interface Product {
  id: number
  name: string
  price: number
}

let productRepo = new Repository<Product>()
productRepo.add({ id: 1, name: '手机', price: 2999 })

条件类型

typescript
type IsString<T> = T extends string ? true : false

type A = IsString<string>  // true
type B = IsString<number>  // false

// 实用工具类型
type NonNullable<T> = T extends null | undefined ? never : T

type MaybeString = string | null
type DefinitelyString = NonNullable<MaybeString> // string

枚举

数字枚举

typescript
enum Direction {
  Up,      // 0
  Down,    // 1
  Left,    // 2
  Right    // 3
}

let dir: Direction = Direction.Up
console.info(dir) // 0

// 指定起始值
enum Color {
  Red = 1,
  Green,   // 2
  Blue     // 3
}

// 完全指定值
enum HttpStatus {
  OK = 200,
  NotFound = 404,
  ServerError = 500
}

console.info(HttpStatus.OK)         // 200
console.info(HttpStatus['OK'])      // 200
console.info(HttpStatus[200])       // OK

字符串枚举

typescript
enum DirectionStr {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT'
}

console.info(DirectionStr.Up) // UP

异构枚举

typescript
enum Mixed {
  No = 0,
  Yes = 'YES',
  Maybe = 2
}

常量枚举

typescript
const enum DirectionConst {
  Up,
  Down,
  Left,
  Right
}

// 编译时内联,不会生成对象
let directions = [DirectionConst.Up, DirectionConst.Down]

类型别名、联合类型与交叉类型

类型别名

typescript
// 基本类型别名
type UserID = number
type UserName = string

// 对象类型别名
type Point = {
  x: number
  y: number
}

let p: Point = { x: 10, y: 20 }

// 联合类型别名
type Status = 'pending' | 'success' | 'error'
type ID = string | number

// 函数类型别名
type Callback = (data: string) => void

// 与接口的区别:类型别名可以为任意类型起名字
type StringOrNumber = string | number
type TupleType = [string, number]

联合类型

typescript
function printId(id: number | string): void {
  if (typeof id === 'string') {
    console.info(id.toUpperCase())
  } else {
    console.info(id.toFixed(2))
  }
}

printId(101)      // 101.00
printId('abc')    // ABC

// 字面量联合类型
type EventType = 'click' | 'dblclick' | 'mouseup' | 'mousedown'

function handleEvent(event: EventType): void {
  console.info(`处理 ${event} 事件`)
}

交叉类型

typescript
interface Colorful {
  color: string
}

interface Circle {
  radius: number
}

type ColorfulCircle = Colorful & Circle

let cc: ColorfulCircle = {
  color: 'red',
  radius: 42
}

// 多个接口交叉
interface Employee {
  name: string
}

interface Manager {
  department: string
}

type ManagerEmployee = Employee & Manager

let manager: ManagerEmployee = {
  name: '张三',
  department: '技术部'
}

类型推断与类型断言

类型推断

typescript
// 变量类型推断
let x = 3           // 推断为 number
let y = 'hello'     // 推断为 string
let z = [1, 2]      // 推断为 number[]

// 函数返回值推断
function add(a: number, b: number) {
  return a + b      // 推断返回 number
}

// 上下文类型推断
window.onscroll = function(event) {
  // event 被推断为 Event 类型
  console.info(event.target)
}

类型断言

typescript
// as 语法
let someValue: unknown = 'this is a string'
let strLength: number = (someValue as string).length

// 尖括号语法(在 TSX 中不可用)
let anotherLength: number = (<string>someValue).length

// 非空断言
function process(value: string | null) {
  const len = value!.length  // 确定 value 不为 null
}

// 双重断言
let value: unknown = 'hello'
let num = (value as unknown as number) // 谨慎使用

注意

类型断言不会进行运行时检查,仅在编译时起作用。如果断言错误,可能导致运行时异常。

装饰器

ArkTS 使用装饰器实现声明式 UI 和状态管理。以下是所有核心装饰器的详细说明。

组件装饰器

@Entry

标记入口组件,每个页面必须有且只有一个:

typescript
@Entry
@Component
struct Index {
  build() {
    Column() {
      Text('首页')
    }
  }
}

@Component

标记自定义组件:

typescript
@Component
struct MyComponent {
  build() {
    Row() {
      Text('自定义组件')
    }
  }
}

状态管理装饰器

@State

组件内部状态,变化触发 UI 刷新:

typescript
@Entry
@Component
struct CounterPage {
  @State count: number = 0

  build() {
    Column() {
      Text(`点击次数: ${this.count}`)
        .fontSize(30)

      Button('增加')
        .onClick(() => {
          this.count++
        })
    }
  }
}

规则说明:

特性说明
同步类型不与父组件同步
允许类型Object、class、string、number、boolean、enum、Array、Date、Map、Set
初始值必须本地初始化
外部访问不支持,仅组件内访问

@Prop

父子单向同步,父变子变,子变父不变:

typescript
@Component
struct Child {
  @Prop count: number = 0

  build() {
    Column() {
      Text(`子组件: ${this.count}`)
      Button('子组件修改')
        .onClick(() => {
          this.count++ // 仅本地生效,不会同步回父组件
        })
    }
  }
}

@Entry
@Component
struct Parent {
  @State parentCount: number = 10

  build() {
    Column() {
      Text(`父组件: ${this.parentCount}`)
      Button('父组件修改')
        .onClick(() => {
          this.parentCount++
        })
      Child({ count: this.parentCount })
    }
  }
}

父子双向同步:

typescript
@Component
struct LinkChild {
  @Link value: number

  build() {
    Column() {
      Text(`双向绑定: ${this.value}`)
      Button('子组件修改')
        .onClick(() => {
          this.value++ // 会同步回父组件
        })
    }
  }
}

@Entry
@Component
struct LinkParent {
  @State parentValue: number = 100

  build() {
    Column() {
      Text(`父组件: ${this.parentValue}`)
      Button('父组件修改')
        .onClick(() => {
          this.parentValue++
        })
      // 使用 $ 语法传递引用
      LinkChild({ value: $parentValue })
    }
  }
}

提示

@Link 不能在 @Entry 装饰的组件中使用,且禁止本地初始化。

@Provide / @Consume

跨层级双向同步:

typescript
@Entry
@Component
struct ProvideParent {
  @Provide themeColor: string = '#FF0000'

  build() {
    Column() {
      Text('祖先组件')
        .fontColor(this.themeColor)
      MiddleComponent()
    }
  }
}

@Component
struct MiddleComponent {
  build() {
    Column() {
      Text('中间组件')
      DeepChild()
    }
  }
}

@Component
struct DeepChild {
  @Consume themeColor: string

  build() {
    Column() {
      Text('深层子组件')
        .fontColor(this.themeColor)
      Button('修改主题色')
        .onClick(() => {
          this.themeColor = '#00FF00'
        })
    }
  }
}

绑定方式:

方式语法
同名绑定@Provide color: string + @Consume color: string
别名绑定@Provide('theme') color: string + @Consume('theme') c: string

嵌套对象属性变化观察:

typescript
@Observed
class Book {
  title: string
  constructor(title: string) {
    this.title = title
  }
}

@Observed
class Bag {
  book: Book
  constructor(book: Book) {
    this.book = book
  }
}

@Component
struct BookCard {
  @ObjectLink book: Book

  build() {
    Column() {
      Text(`书名: ${this.book.title}`)
      Button('修改书名')
        .onClick(() => {
          this.book.title = '新书名'
        })
    }
  }
}

@Entry
@Component
struct ObservedDemo {
  @State bag: Bag = new Bag(new Book('旧书名'))

  build() {
    Column() {
      BookCard({ book: this.bag.book })
    }
  }
}

注意

@ObjectLink 装饰的变量是只读的,不能被赋值(this.obj = newObj 会报错),但可以修改属性。

UI 构建装饰器

@Builder

自定义构建函数,复用 UI 片段:

typescript
// 全局 Builder
@Builder
function GlobalHeader(title: string) {
  Row() {
    Text(title)
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
  }
  .width('100%')
  .height(50)
  .backgroundColor('#F1F3F5')
}

@Entry
@Component
struct BuilderDemo {
  @State title: string = '页面标题'

  // 局部 Builder
  @Builder
  CustomFooter() {
    Row() {
      Text('底部内容')
    }
    .width('100%')
    .height(60)
  }

  build() {
    Column() {
      GlobalHeader(this.title)
      Text('页面内容')
      this.CustomFooter()
    }
  }
}

参数传递规则:

传递方式说明
按值传递默认方式,状态变化不触发 Builder 刷新
按引用传递传入对象字面量,状态变化触发刷新
typescript
class Params {
  text: string = ''
}

@Builder
function ReferenceBuilder($$: Params) {
  Text($$.text)
}

// 按引用传递
ReferenceBuilder({ text: this.message })

@Extend

扩展原生组件样式:

typescript
@Extend(Text)
function fancyText(size: number, color: ResourceColor) {
  .fontSize(size)
  .fontColor(color)
  .fontWeight(FontWeight.Bold)
}

@Entry
@Component
struct ExtendDemo {
  build() {
    Column() {
      Text('普通文本')
      Text('样式扩展文本').fancyText(24, Color.Red)
    }
  }
}

提示

@Extend 仅支持全局定义,不支持在组件内部定义。

@Styles

通用样式复用:

typescript
// 全局 Styles
@Styles
function globalCard() {
  .width('90%')
  .padding(16)
  .backgroundColor(Color.White)
  .borderRadius(12)
}

@Entry
@Component
struct StylesDemo {
  @State heightValue: number = 100

  // 组件内 Styles
  @Styles
  dynamicStyle() {
    .height(this.heightValue)
    .backgroundColor(Color.Yellow)
    .onClick(() => {
      this.heightValue = 200
    })
  }

  build() {
    Column() {
      Text('全局样式')
        .globalCard()

      Text('动态样式')
        .dynamicStyle()
    }
  }
}

注意

@Styles 不能有参数,仅支持通用属性和通用事件。

@CustomDialog

自定义弹窗:

typescript
@CustomDialog
struct CustomAlert {
  @Prop title: string
  @Prop message: string
  controller: CustomDialogController

  build() {
    Column() {
      Text(this.title)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      Text(this.message)
        .margin(10)
      Button('确定')
        .onClick(() => {
          this.controller.close()
        })
    }
    .padding(20)
    .backgroundColor(Color.White)
    .borderRadius(16)
  }
}

@Entry
@Component
struct DialogDemo {
  dialogController: CustomDialogController = new CustomDialogController({
    builder: CustomAlert({
      title: '提示',
      message: '这是一个自定义弹窗'
    })
  })

  build() {
    Column() {
      Button('显示弹窗')
        .onClick(() => {
          this.dialogController.open()
        })
    }
  }
}

其他装饰器

@Watch

监听状态变量变化:

typescript
@Entry
@Component
struct WatchDemo {
  @State @Watch('onCountChanged') count: number = 0
  @State message: string = ''

  onCountChanged(propName: string): void {
    this.message = `计数变化为: ${this.count}`
    console.info(`属性 ${propName} 发生变化`)
  }

  build() {
    Column() {
      Text(this.message)
      Text(`计数: ${this.count}`)
      Button('增加')
        .onClick(() => {
          this.count++
        })
    }
  }
}

提示

@Watch 在初始化时不会触发,仅在状态变量后续变化时触发。

@Track

属性级精确更新:

typescript
class LogTrack {
  @Track logInfo: string = ''
  owner: string = ''
  id: number = 0
}

@Entry
@Component
struct TrackDemo {
  @State log: LogTrack = new LogTrack()

  build() {
    Column() {
      // 仅当 logInfo 变化时刷新
      Text(this.log.logInfo)
      Button('修改 logInfo')
        .onClick(() => {
          this.log.logInfo = '新日志'
        })
      // owner 未被 @Track 装饰,不能在 UI 中使用
    }
  }
}

注意

如果类中使用了 @Track,则非 @Track 装饰的属性不能在 UI 中使用,否则运行时报错。

@Trace

深度观测(配合 V2 装饰器使用):

typescript
@ObservedV2
class Info {
  @Trace name: string = ''
  @Trace age: number = 0
}

@ComponentV2
struct TraceDemo {
  @Local info: Info = { name: 'Tom', age: 25 }

  build() {
    Column() {
      Text(`${this.info.name}, ${this.info.age}`)
      Button('修改')
        .onClick(() => {
          this.info.name = 'Jerry'
        })
    }
  }
}

模块系统

导出 Export

typescript
// utils.ets
// 命名导出
export function add(a: number, b: number): number {
  return a + b
}

export class Calculator {
  multiply(a: number, b: number): number {
    return a * b
  }
}

export const PI: number = 3.14159

// 默认导出
export default function greet(name: string): string {
  return `Hello, ${name}!`
}

导入 Import

typescript
// 命名导入
import { add, Calculator, PI } from './utils'

// 默认导入
import greet from './utils'

// 混合导入
import greet, { add, Calculator } from './utils'

// 整体导入
import * as Utils from './utils'

// 使用
const sum = add(1, 2)
const calc = new Calculator()
const product = calc.multiply(3, 4)
console.info(Utils.PI)

// 动态导入
async function loadModule() {
  const module = await import('./utils')
  module.add(1, 2)
}

命名空间

typescript
// 定义命名空间
namespace Validation {
  export interface StringValidator {
    isValid(s: string): boolean
  }

  export class EmailValidator implements StringValidator {
    isValid(s: string): boolean {
      return s.includes('@')
    }
  }

  const numberRegexp = /^[0-9]+$/

  export class ZipCodeValidator implements StringValidator {
    isValid(s: string): boolean {
      return s.length === 5 && numberRegexp.test(s)
    }
  }
}

// 使用命名空间
let emailValidator = new Validation.EmailValidator()
console.info(emailValidator.isValid('test@example.com')) // true

异步编程

Promise

typescript
// 创建 Promise
function fetchData(): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('数据加载完成')
    }, 1000)
  })
}

// Promise 链式调用
fetchData()
  .then(data => {
    console.info(data)
    return '下一步'
  })
  .then(result => {
    console.info(result)
  })
  .catch(error => {
    console.error('错误:', error)
  })
  .finally(() => {
    console.info('无论成功失败都执行')
  })

// Promise 静态方法
let p1 = Promise.resolve(42)
let p2 = Promise.reject('错误')

Promise.all([p1, fetchData()])
  .then(results => {
    console.info(results) // [42, '数据加载完成']
  })

Promise.race([p1, p2])
  .then(result => {
    console.info(result)
  })

async/await

typescript
// 定义异步函数
async function loadUserData(): Promise<string> {
  let data = await fetchData()
  return `用户: ${data}`
}

// 使用 try/catch 处理错误
async function load() {
  try {
    const result = await loadUserData()
    console.info(result)
  } catch (error) {
    console.error('加载失败:', error)
  }
}

// 并行执行
async function loadMultiple() {
  const [users, posts] = await Promise.all([
    fetchUsers(),
    fetchPosts()
  ])
  console.info('全部加载完成')
}

// 辅助函数
async function fetchUsers(): Promise<string[]> {
  return ['user1', 'user2']
}

async function fetchPosts(): Promise<string[]> {
  return ['post1', 'post2']
}

并发任务 TaskPool

TaskPool 用于执行耗时计算任务,避免阻塞 UI 线程:

typescript
import { taskpool } from '@kit.ArkTS'

// 定义并发任务函数
@Concurrent
function calculateSum(a: number, b: number): number {
  return a + b
}

@Concurrent
function heavyComputation(n: number): number {
  let sum = 0
  for (let i = 0; i < n; i++) {
    sum += i
  }
  return sum
}

@Entry
@Component
struct TaskPoolDemo {
  @State result: string = ''

  async executeTask() {
    // 创建任务
    let task: taskpool.Task = new taskpool.Task(calculateSum, 10, 20)

    // 执行任务
    let result = await taskpool.execute(task) as number
    this.result = `计算结果: ${result}`
  }

  async executeHeavyTask() {
    let task = new taskpool.Task(heavyComputation, 1000000)
    let result = await taskpool.execute(task) as number
    this.result = `大数计算结果: ${result}`
  }

  build() {
    Column() {
      Text(this.result)
      Button('执行简单任务')
        .onClick(() => this.executeTask())
      Button('执行耗时任务')
        .onClick(() => this.executeHeavyTask())
    }
  }
}

Worker 多线程

Worker 用于长时间运行的后台任务:

typescript
// worker.ts
import { worker } from '@kit.ArkTS'

let parentPort = worker.workerPort

parentPort.onmessage = function(e: MessageEvents) {
  let data = e.data
  // 处理数据
  let result = data * 2
  parentPort.postMessage(result)
}

// 主线程
import { worker } from '@kit.ArkTS'

@Entry
@Component
struct WorkerDemo {
  private myWorker: worker.ThreadWorker = new worker.ThreadWorker('entry/ets/workers/worker.ts')
  @State result: string = ''

  aboutToAppear() {
    this.myWorker.onmessage = (e: MessageEvents) => {
      this.result = `Worker 结果: ${e.data}`
    }
  }

  aboutToDisappear() {
    this.myWorker.terminate()
  }

  sendMessage() {
    this.myWorker.postMessage(42)
  }

  build() {
    Column() {
      Text(this.result)
      Button('发送消息给 Worker')
        .onClick(() => this.sendMessage())
    }
  }
}

错误处理

try/catch/finally

typescript
function riskyOperation(): void {
  throw new Error('发生错误')
}

function handleError(): void {
  try {
    riskyOperation()
    console.info('这行不会执行')
  } catch (error) {
    // 捕获错误
    if (error instanceof Error) {
      console.error('错误信息:', error.message)
      console.error('错误堆栈:', error.stack)
    }
  } finally {
    // 无论是否发生错误都会执行
    console.info('清理资源')
  }
}

// 在 async 函数中使用
try {
  let result = await fetchData()
} catch (error) {
  console.error('异步操作失败:', error)
}

自定义错误类型

typescript
class ValidationError extends Error {
  constructor(message: string) {
    super(message)
    this.name = 'ValidationError'
  }
}

class NetworkError extends Error {
  statusCode: number

  constructor(message: string, statusCode: number) {
    super(message)
    this.name = 'NetworkError'
    this.statusCode = statusCode
  }
}

function validateAge(age: number): void {
  if (age < 0) {
    throw new ValidationError('年龄不能为负数')
  }
  if (age > 150) {
    throw new ValidationError('年龄不合法')
  }
}

// 使用
try {
  validateAge(-5)
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('验证错误:', error.message)
  }
}

错误处理最佳实践

typescript
// 可选链和空值合并
let userName = user?.profile?.name ?? '匿名用户'

// 类型守卫
function processValue(value: string | number | null): void {
  if (value === null) {
    console.info('值为 null')
    return
  }

  if (typeof value === 'string') {
    console.info('字符串:', value.toUpperCase())
  } else {
    console.info('数字:', value.toFixed(2))
  }
}

ArkTS 与 TypeScript 差异总结

特性TypeScriptArkTS
any 类型允许禁止
动态属性允许 obj.newProp = 1禁止
eval()允许禁止
new Function()允许禁止
声明式 UI不支持@Component + build()
状态管理不支持@State, @Prop, @Link
并发模型单线程TaskPool + Worker
装饰器实验性核心特性
类型推断宽松严格,必须显式声明
Sendable 对象不支持支持跨线程共享
文件扩展名.ts.ets
typescript
// TypeScript 允许,ArkTS 禁止
let dynamic: any = 1
dynamic = 'string'

let obj = {}
obj['newKey'] = 'value'

eval('console.info("hello")')

// ArkTS 正确写法
let strict: number = 1

interface MyObject {
  newKey: string
}
let obj2: MyObject = { newKey: 'value' }

最佳实践

  1. 始终显式声明类型:不要依赖类型推断,提高代码可读性
  2. 使用接口定义数据结构:比类更轻量,适合数据契约
  3. 避免使用 any:会失去类型检查的保护
  4. 合理使用枚举:替代魔法数字,提高代码可维护性
  5. 异步操作使用 async/await:代码更清晰,错误处理更方便
  6. 状态管理选择合适的装饰器
    • 组件内部状态 -> @State
    • 父传子单向 -> @Prop
    • 父子双向 -> @Link
    • 跨层级共享 -> @Provide/@Consume
    • 嵌套对象观察 -> @Observed/@ObjectLink
  7. 耗时操作放入 TaskPool:避免阻塞 UI 主线程
  8. 使用 @Track 优化性能:精确控制属性级更新,避免冗余刷新