惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Register - Security
The Register - Security
The Cloudflare Blog
Last Week in AI
Last Week in AI
月光博客
月光博客
Security Latest
Security Latest
Project Zero
Project Zero
博客园 - 司徒正美
AWS News Blog
AWS News Blog
雷峰网
雷峰网
博客园 - 聂微东
C
Cybersecurity and Infrastructure Security Agency CISA
P
Palo Alto Networks Blog
人人都是产品经理
人人都是产品经理
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
Martin Fowler
Martin Fowler
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Microsoft Azure Blog
Microsoft Azure Blog
B
Blog RSS Feed
A
About on SuperTechFans
V
V2EX
P
Proofpoint News Feed
腾讯CDC
S
Schneier on Security
K
Kaspersky official blog
Google Online Security Blog
Google Online Security Blog
Recorded Future
Recorded Future
H
Hacker News: Front Page
Application and Cybersecurity Blog
Application and Cybersecurity Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
C
CERT Recently Published Vulnerability Notes
aimingoo的专栏
aimingoo的专栏
博客园 - 叶小钗
美团技术团队
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
V
Vulnerabilities – Threatpost
C
Cisco Blogs
PCI Perspectives
PCI Perspectives
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 【当耐特】
N
News and Events Feed by Topic
Google DeepMind News
Google DeepMind News
Hugging Face - Blog
Hugging Face - Blog
阮一峰的网络日志
阮一峰的网络日志
P
Privacy International News Feed
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
W
WeLiveSecurity
Spread Privacy
Spread Privacy
S
Securelist

博客园 - thammer

03 — std::vector 进阶篇 02 — 迭代器基础 01 — std::vector 基础篇 Day 17:Promise 基础 Day 16 - 读懂 TypeScript 声明文件(.d.ts) Day 15 - ArkTS 模块系统 Day 14 - ArkTS 错误处理 Day 12 - 泛型与阶段三总结 Day 11 - Interface 与类型契约 Day 10 - 继承与多态 Day 09 - Class 基础 Day 08 - 函数进阶与阶段总结 Day 07 - 函数类型与高阶函数 Day 06 - 函数基础 Day 05 - 数组和元组深入 Day 04 - 循环与迭代 Day 03 - 条件控制 Day 02 - 运算符与表达式 Day 01 - 变量与类型基础 Day 00 - 环境准备 C++虚函数 C++ 多继承 C++成员访问权限以及继承权限 C++ 成员初始化机制总结笔记
Day 13 - ArkTS 类型系统进阶
thammer · 2026-04-16 · via 博客园 - thammer

目标:掌握枚举、Type 别名、特殊类型与类型操作,理解 ArkTS 类型限制
预计时间:1-1.5小时


课前思考

回顾前面学习的类型系统:

// 基本类型
let count: number = 10;
let name: string = "张三";
let active: boolean = true;

// 数组类型
let scores: number[] = [85, 92, 78];

// 接口类型
interface Person {
    name: string;
    age: number;
}

思考问题:

  1. 如何表示一组有限的常量值(如状态、方向、级别)?
  2. 如何为基本类型或复杂类型起别名提高可读性?
  3. ArkTS 对类型系统有哪些特殊限制?

第一部分:枚举(Enum)

1.1 为什么需要枚举

问题:魔法数字可读性差

// 不用枚举:0、1、2 代表什么?
let status: number = 0;  // 离线?在线?故障?

function handleStatus(s: number): void {
    if (s === 0) {
        console.log("离线");
    } else if (s === 1) {
        console.log("在线");
    } else if (s === 2) {
        console.log("故障");
    }
}

枚举解决方案:

enum DeviceStatus {
    OFFLINE,   // 0
    ONLINE,    // 1
    ERROR      // 2
}

let status: DeviceStatus = DeviceStatus.ONLINE;
console.log(`结果:${status}`);  // 1

// 判断状态
if (status === DeviceStatus.ONLINE) {
    console.log("设备在线");
}

1.2 数值枚举

自动递增规则:

  • 第一个成员默认值为 0
  • 后续成员自动递增 1
enum Priority {
    LOW,      // 0
    MEDIUM,   // 1
    HIGH      // 2
}

// 显式指定初始值
enum Direction {
    UP = 10,      // 10
    DOWN = 20,    // 20
    LEFT = 30,    // 30
    RIGHT = 40    // 40
}

// 部分指定,后续自动递增
enum Status {
    PENDING = 1,    // 1
    PROCESSING,     // 2
    COMPLETED,      // 3
    FAILED          // 4
}

1.3 字符串枚举

enum LogLevel {
    DEBUG = "DEBUG",
    INFO = "INFO",
    WARN = "WARN",
    ERROR = "ERROR"
}

let level: LogLevel = LogLevel.INFO;
console.log(`结果:${level}`);  // "INFO"

function logMessage(level: LogLevel, message: string): void {
    console.log(`[${level}] ${message}`);
}

logMessage(LogLevel.ERROR, "连接超时");  // [ERROR] 连接超时

字符串枚举优势:

  • 可读性更好
  • 调试时更易识别
  • 适合日志级别、错误码等场景

1.4 枚举的使用场景

场景1:命令类型

enum CommandType {
    TURN_ON = 0x01,
    TURN_OFF = 0x02,
    SET_BRIGHTNESS = 0x03,
    GET_STATUS = 0x04
}

class DeviceController {
    executeCommand(cmd: CommandType, param?: number): string {
        if (cmd === CommandType.TURN_ON) {
            return "设备已开启";
        } else if (cmd === CommandType.TURN_OFF) {
            return "设备已关闭";
        } else if (cmd === CommandType.SET_BRIGHTNESS) {
            return `亮度设置为 ${param}`;
        } else if (cmd === CommandType.GET_STATUS) {
            return "当前状态:正常";
        }
        return "未知命令";
    }
}

场景2:状态机

enum ConnectionState {
    DISCONNECTED,
    CONNECTING,
    CONNECTED,
    RECONNECTING
}

class NetworkManager {
    private state: ConnectionState = ConnectionState.DISCONNECTED;
    
    connect(): void {
        if (this.state === ConnectionState.DISCONNECTED) {
            this.state = ConnectionState.CONNECTING;
            // 执行连接...
        }
    }
}

1.5 ArkTS 枚举限制

❌ 禁止:混合类型枚举

// ❌ 编译错误:不能同时包含数字和字符串
enum MixedEnum {
    A = 1,      // number
    B = "B"     // string - 错误!
}

✅ 正确做法:

// 纯数值枚举
enum NumericEnum {
    A = 1,
    B = 2,
    C = 3
}

// 纯字符串枚举
enum StringEnum {
    A = "A",
    B = "B",
    C = "C"
}

对比 C++:

// C++11 推荐 enum class
enum class Status {
    OFFLINE = 0,
    ONLINE = 1,
    ERROR = 2
};

Status s = Status::ONLINE;  // 作用域更强

第二部分:Type 别名

2.1 基本类型别名

// 为基本类型起别名
type ID = number;
type Name = string;
type Price = number;
type IsActive = boolean;

// 使用
let userId: ID = 1001;
let productName: Name = "手机";
let productPrice: Price = 2999.99;
let status: IsActive = true;

作用:

  • 提高代码可读性
  • 表达业务含义
  • 便于后期统一修改

2.2 联合类型别名

// 定义有限的状态值
type Status = "pending" | "processing" | "completed" | "failed";
type Priority = "low" | "medium" | "high";
type Theme = "light" | "dark" | "auto";

// 使用
let taskStatus: Status = "pending";
let taskPriority: Priority = "high";

function updateStatus(newStatus: Status): void {
    console.log(`状态更新为:${newStatus}`);
}

// 只能赋值预定义的值
// updateStatus("unknown");  // ❌ 编译错误

2.3 函数类型别名

// 定义函数类型
type ClickHandler = (x: number, y: number) => void;
type DataTransformer = (input: string) => number;
type Validator = (value: string) => boolean;

// 使用
let handleClick: ClickHandler = (x: number, y: number): void => {
    console.log(`点击位置:(${x}, ${y})`);
};

let parseNumber: DataTransformer = (input: string): number => {
    return parseInt(input, 10);
};

let isEmail: Validator = (value: string): boolean => {
    return value.indexOf("@") > 0;
};

// 在接口中使用
type CompareFn = (a: number, b: number) => number;

interface Sorter {
    compare: CompareFn;
    sort(data: number[]): number[];
}

2.4 ArkTS 对 type 的限制

❌ 禁止:用 type 定义对象类型

// ❌ ArkTS 编译错误
type Person = {
    name: string;
    age: number;
};

// ✅ 正确做法:使用 interface
interface Person {
    name: string;
    age: number;
}

❌ 禁止:交叉类型

interface A {
    a: number;
}

interface B {
    b: string;
}

// ❌ ArkTS 编译错误
type AB = A & B;

// ✅ 正确做法:使用接口继承
interface AB extends A, B {
    // 自动包含 a 和 b
}

第三部分:特殊类型与类型操作

3.1 never 类型(✅ ArkTS 完全支持)

概念:表示"永远不会发生的值",是所有类型的子类型

使用场景1:抛出异常的函数返回类型

function throwError(message: string): never {
    throw new Error(message);
}

使用场景2:穷尽检查(exhaustive check)

在 switch 的 default 分支中确保所有 case 都被处理:

enum Status {
    PENDING = "pending",
    SUCCESS = "success",
    FAILED = "failed"
}

function handleStatus(status: Status): string {
    switch (status) {
        case Status.PENDING:
            return "处理中...";
        case Status.SUCCESS:
            return "成功!";
        case Status.FAILED:
            return "失败!";
        default:
            // 穷尽检查:如果上面漏了某个 case,这里会编译报错
            const check: never = status;
            return check;
    }
}

对比 C++:

// C++ 中 [[noreturn]] 属性标注的函数
[[noreturn]] void throwError(const std::string& message) {
    throw std::runtime_error(message);
}

注意nevervoid 的区别

  • void:表示没有返回值(函数正常结束)
  • never:表示永远不会正常结束(抛出异常或无限循环)

3.2 as 类型断言(⚠️ 部分支持)

概念:手动告诉编译器某个值的具体类型

语法value as TargetType

使用场景:当你比编译器更了解某个值的实际类型时

示例:父类引用转换为子类类型(Day 10 已学继承,可以用这个场景)

class Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    move(): void {
        console.log("动物在移动");
    }
}

class Dog extends Animal {
    bark(): void {
        console.log("汪汪!");
    }
}

// 父类引用指向子类对象
let animal: Animal = new Dog("旺财");

// 需要调用 Dog 特有的方法时,使用 as 断言
let dog: Dog = animal as Dog;
dog.bark();  // 汪汪!

⚠️ ArkTS 限制as const 断言不支持(规则 arkts-no-as-const)

// ❌ ArkTS 不支持 as const
// let arr = [1, 2, 3] as const;

// ✅ ArkTS 正确写法
let arr: number[] = [1, 2, 3];

安全建议:优先使用 instanceof 类型守卫(Day 03 已学),as 断言是最后手段

// ✅ 更安全的做法:使用 instanceof
if (animal instanceof Dog) {
    animal.bark();  // 类型守卫自动收窄为 Dog
}

对比 C++:

// 类似 C++ 的 static_cast,编译期检查但不保证运行时安全
Dog* dog = static_cast<Dog*>(animalPtr);

3.3 ArkTS 禁用的类型特性

这一节集中说明 ArkTS 相比 TypeScript 不支持的类型特性,让你了解边界。

3.3.1 unknown 类型(❌ 不支持)

在标准 TypeScript 中,unknownany 的安全替代——接收任何值但使用前必须类型检查。

ArkTS 同时禁用 anyunknown(规则 arkts-no-any-unknown)。

替代方案:使用显式的联合类型或 Object 类型

// ❌ TypeScript 的写法(ArkTS 不允许)
// let value: unknown = 42;

// ✅ ArkTS 的写法:用联合类型
let value: number | string = 42;

// 或者使用 Object 类型(需要时再进行类型判断)
let obj: Object = { name: "张三" };

3.3.2 字面量类型(❌ 不支持)

在标准 TypeScript 中,可以用具体的字符串/数字值作为类型:

// ❌ TypeScript 的字面量类型(ArkTS 不允许)
// type Direction = "up" | "down" | "left" | "right";

ArkTS 不支持字面量类型(规则 arkts-no-as-const)。

替代方案:使用枚举(Day 13 第一部分已学)

// ✅ ArkTS 用枚举替代
enum Direction {
    UP = "up",
    DOWN = "down",
    LEFT = "left",
    RIGHT = "right"
}

let dir: Direction = Direction.UP;
console.log(`方向:${dir}`);  // 方向:up

第四部分:ArkTS OOP 限制速查表

限制项 错误示例 正确做法
对象类型必须用 interface type Person = {...} interface Person {...}
禁止索引签名 [key: string]: number 使用 Record<K, V>Map
禁止交叉类型 type AB = A & B interface AB extends A, B
interface 不支持 readonly readonly x: number 使用 Readonly<T> 工具类型
对象字面量需配合 interface let x = {a: 1} let x: MyInterface = {...}

4.1 Readonly 使用示例

interface Point {
    x: number;
    y: number;
}

// 创建只读版本
type ReadonlyPoint = Readonly<Point>;

let p1: Point = { x: 10, y: 20 };
p1.x = 100;  // ✅ 可以修改

let p2: ReadonlyPoint = { x: 10, y: 20 };
// p2.x = 100;  // ❌ 编译错误:只读属性

注意: Readonly<T> 是 ArkTS 提供的工具类型,Day 12 学习泛型后会理解其原理。


4.2 Record<K, V> 使用示例

// 替代索引签名
let scores: Record<string, number> = {
    "张三": 85,
    "李四": 92
};

// 或使用 Map
let scoreMap: Map<string, number> = new Map();
scoreMap.set("张三", 85);

第五部分:小结与练习

5.1 知识点对比总结表

概念 核心语法 适用场景
枚举(Enum) enum Status { A, B } 有限常量值集合
数值枚举 enum A { X = 1, Y } 状态码、命令类型
字符串枚举 enum B { X = "X" } 日志级别、错误类型
Type 别名 type ID = number 基本类型、联合类型、函数类型
联合类型 type S = "a" | "b" 有限字符串值

5.2 使用原则

场景 推荐
有限常量值 enum
基本类型别名 type
联合类型 type
函数类型 type
对象类型 interface(ArkTS 强制)
扩展对象类型 interface extends

练习题

练习1:枚举定义

// 1. 定义 HttpStatus 枚举:
//    - OK = 200
//    - NOT_FOUND = 404
//    - SERVER_ERROR = 500

// 2. 定义 UserRole 字符串枚举:
//    - ADMIN = "admin"
//    - USER = "user"
//    - GUEST = "guest"

// 3. 编写函数 checkPermission(role: UserRole): boolean
//    - ADMIN 返回 true
//    - 其他返回 false

练习2:Type 别名应用

// 1. 定义以下类型别名:
//    - UserId: number
//    - Email: string
//    - ApiResponse: { code: number; data: object; message: string }

// 2. 定义 StatusCode 联合类型:
//    - 200 | 404 | 500

// 3. 定义 Handler 函数类型:
//    - (req: object) => ApiResponse

练习3:ArkTS 限制改写

// 将以下不符合 ArkTS 规范的代码改写:

// 原代码(不符合规范):
type Config = {
    key: string;
    value: any;
    [key: string]: any;  // 索引签名
};

// 请改写为符合 ArkTS 规范的代码

附录:C++ vs ArkTS 类型系统对比

特性 C++ ArkTS
枚举 enum / enum class enum(禁止混合类型)
类型别名 typedef / using type
联合类型 std::variant (C++17) type X = A | B
函数类型 函数指针 / std::function type Fn = (...) => T
对象类型 struct / class interface
交叉类型 多重继承 不支持(用接口继承)
never 类型 [[noreturn]] never
类型断言 static_cast / dynamic_cast as(部分支持)
unknown 类型 - 不支持
字面量类型 - 不支持(用枚举替代)

完成本课后,你将掌握:

  • 使用枚举替代魔法数字
  • 使用 Type 别名提高代码可读性
  • 理解 never 类型和 as 类型断言的用法
  • 了解 ArkTS 禁用的类型特性及其替代方案
  • 理解 ArkTS 类型系统的限制和最佳实践