Appearance
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
| 场景 | Interface | Type |
|---|---|---|
| 对象结构定义 | ✅ 支持合并 | ❌ |
| 联合类型(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) // 2005.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 的优势
- 明确的类型约束:编译器能精确检查 key 和 value 类型
- Hidden Class 优化:比
{}字面量性能更好 - 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 的使用场景区分和泛型的约束技巧。准备一个实际项目中的泛型使用示例会很加分。