Skip to content

ArkTS 类与接口

理解 struct vs class 的使用场景,接口的设计模式,以及泛型在 ArkTS 中的应用。


1. class 在 ArkTS 中的定位

ArkTS 中的 class 用于纯逻辑处理,不能用于 UI 组件。

典型使用场景

  • 数据模型(Model/DTO)
  • 工具类(Utility)
  • 服务类(Service)
  • 业务逻辑封装
typescript
// 数据模型
class User {
    constructor(
        public id: number,
        public name: string,
        public email: string,
        private _age: number
    ) {}

    get age(): number {
        return this._age
    }

    set age(value: number) {
        if (value > 0 && value < 150) {
            this._age = value
        }
    }

    // 业务方法
    isAdult(): boolean {
        return this._age >= 18
    }

    // 静态方法
    static createGuest(): User {
        return new User(0, 'Guest', 'guest@default.com', 0)
    }
}

struct vs class 决策树

你需要创建一个组件吗?
├─ 是 → 使用 struct + @Component(不可继承,必须有 build())
└─ 否 → 使用 class(可继承,纯逻辑)

2. interface 详解

2.1 接口定义

typescript
// 对象接口
interface Point {
    x: number
    y: number
}

interface Rect {
    topLeft: Point
    bottomRight: Point
    width(): number
    height(): number
}

// 函数接口
interface FetchFunc {
    (url: string, options?: RequestOptions): Promise<Response>
}

// 类接口(用于约束实现)
interface IStorage {
    get(key: string): string | null
    set(key: string, value: string): void
    delete(key: string): void
}

// 实现接口
class LocalStorage implements IStorage {
    private store: Map<string, string> = new Map()

    get(key: string): string | null {
        return this.store.get(key) ?? null
    }

    set(key: string, value: string): void {
        this.store.set(key, value)
    }

    delete(key: string): void {
        this.store.delete(key)
    }
}

2.2 接口的合并(Merge)

typescript
// 多个同名接口自动合并
interface User {
    name: string
}

interface User {
    age: number
}

// User 现在包含 name 和 age
const user: User = {
    name: '小明',
    age: 25
}

💡 关键点:接口支持合并,Type 别名不支持。定义对象结构时优先用 Interface。

2.3 接口的继承

typescript
interface Base {
    id: number
    createdAt: Date
}

interface Extended extends Base {
    name: string
    status: 'active' | 'inactive'
}

// Extended 包含 id, createdAt, name, status
const obj: Extended = {
    id: 1,
    createdAt: new Date(),
    name: '测试',
    status: 'active'
}

3. interface vs type

场景InterfaceType
对象结构定义✅ 支持合并
联合类型(A | B)
交叉类型(A & B)
基本类型别名
元组类型
映射类型
函数签名
typescript
// 只能用 Type 的场景
type Status = 'pending' | 'active' | 'error'
type Pair<T> = [T, T]
type PartialUser = Partial<User>  // 映射类型

4. 泛型(Generics)

4.1 基础泛型

typescript
// 泛型函数
function identity<T>(arg: T): T {
    return arg
}
console.log(identity<string>('Hello'))  // string
console.log(identity<number>(42))        // number

// 泛型接口
interface ApiResponse<T> {
    code: number
    data: T
    message: string
}

// 泛型类
class Cache<K, V> {
    private store = new Map<K, V>()

    set(key: K, value: V): void {
        this.store.set(key, value)
    }

    get(key: K): V | undefined {
        return this.store.get(key)
    }
}

4.2 泛型约束

typescript
// 约束:T 必须包含 length 属性
function getLength<T extends { length: number }>(arg: T): number {
    return arg.length
}

// 约束:T 必须实现某个接口
interface HasId {
    id: number
}

function process<T extends HasId>(item: T): number {
    return item.id  // ✅ 编译器知道 item 有 id
}

// 约束:T 必须 extends keyof U
function getProperty<U, T extends keyof U>(obj: U, key: T): U[T] {
    return obj[key]
}

4.3 泛型默认值

typescript
// 带默认值的泛型
interface ApiResponse<T = any> {
    code: number
    data: T
    message: string
}

// 可以省略泛型参数
const response: ApiResponse = { code: 200, data: {}, message: 'OK' }

4.4 ArkTS 泛型的特殊性

ArkTS 的泛型在编译期进行类型检查,运行时虽然有类型擦除,但保留了部分元数据用于反射。

typescript
// 运行时有限支持反射
class Model<T> {
    getType(): string {
        // 在 ArkTS 中有限支持
        return typeof {} as T
    }
}

5. enum 枚举

5.1 数字枚举

typescript
enum HttpStatus {
    Ok = 200,
    Created = 201,
    BadRequest = 400,
    Unauthorized = 401,
    NotFound = 404,
    ServerError = 500
}

// 反向映射
console.log(HttpStatus[200])     // "Ok"
console.log(HttpStatus.Ok)       // 200

5.2 字符串枚举(推荐)

typescript
enum HttpMethod {
    GET = 'GET',
    POST = 'POST',
    PUT = 'PUT',
    DELETE = 'DELETE'
}

// 编译期更安全,值不可变
const method: HttpMethod = HttpMethod.GET
// method = 'GET'  // ❌ 不允许,必须用枚举值

5.3 常量枚举(零运行时开销)

typescript
const enum LogLevel {
    Debug = 0,
    Info = 1,
    Warn = 2,
    Error = 3
}

function log(level: LogLevel, msg: string) {
    // LogLevel.Debug 在编译时被内联为 0
    if (level >= LogLevel.Debug) {
        console.log(msg)
    }
}

6. Record 类型

6.1 基本用法

typescript
// Record<Keys, Type>:用 Keys 作为 key 类型
type UserMap = Record<string, User>

const users: UserMap = {
    'user1': { id: 1, name: '小明' },
    'user2': { id: 2, name: '小红' }
}

// 数字 key
type ScoreMap = Record<number, number>
const scores: ScoreMap = {
    1: 95,
    2: 87
}

6.2 Record 的优势

  1. 明确的类型约束:编译器能精确检查 key 和 value 类型
  2. Hidden Class 优化:比 {} 字面量性能更好
  3. IDE 自动补全:key 自动提示

💡 面试考点:Record 提供了更明确的类型约束,有利于编译器优化 Hidden Class 的查找效率,比普通的 {} 字面量性能更好。


7. 面试高频考点

Q1: struct 和 class 在 ArkTS 中如何选择?

回答:自定义 UI 组件必须用 struct(不可继承,必须有 build());纯逻辑处理、数据模型用 class(可继承,无 UI 限制)。

Q2: interface 和 Type 的区别?

回答:定义对象结构优先用 Interface(支持合并),定义联合类型/基本类型别名用 Type

Q3: Record 类型的作用?

回答:用键类型构建映射类型,提供明确类型约束,有利于编译器优化 Hidden Class 查找效率。


🐱 小猫提示:类与接口部分面试主要关注 struct/class 的使用场景区分和泛型的约束技巧。准备一个实际项目中的泛型使用示例会很加分。