4、ArkTS语言基础(下):深入理解高级类型、泛型、模块化编程和状态管理的基本概念
好,咱们接着聊。上一节我们把 ArkTS 的基础类型和语法过了一遍,算是把地基打牢了。这一节,咱们要往上盖楼了——高级类型、泛型、模块化,还有状态管理。这几个概念,说白了就是让你写的代码更灵活、更安全、更好维护。
我个人习惯,学新东西一定要先理解它「解决了什么问题」。不然你光记语法,转头就忘。咱们一个一个来。
4.1 高级类型:不只是简单的 string 和 number
你想想看,实际开发中,一个变量可能不止一种类型。比如一个接口返回的数据,成功时是一个对象,失败时是一个错误信息。这时候怎么办?
4.1.1 联合类型(Union Types)
联合类型用 | 符号表示,意思是「可以是这个,也可以是那个」。我在项目中遇到过不少这样的场景,比如用户输入框,可能接收字符串,也可能接收数字。
let input: string | number;
input = "Hello";
input = 42; // 这样也行
嗯,这里要注意:当你使用联合类型时,TypeScript 只会允许你调用所有类型共有的方法。比如 string | number,你只能调用 toString(),因为两者都有。如果你要调用 length,那就得先做类型收窄。
4.1.2 交叉类型(Intersection Types)
交叉类型用 & 符号,意思是「同时满足多个类型」。说白了就是把多个类型合并成一个。我经常用它来组合多个接口。
interface Person {
name: string;
age: number;
}
interface Employee {
employeeId: number;
department: string;
}
type Staff = Person & Employee;
const staff: Staff = {
name: "张三",
age: 30,
employeeId: 1001,
department: "研发部"
};
你看,Staff 类型同时拥有了 Person 和 Employee 的所有属性。这在做多设备协同开发时特别有用——比如一个设备信息对象,可能同时包含基础信息和设备专属信息。
4.1.3 类型别名(Type Aliases)
类型别名就是给一个类型起个新名字。用 type 关键字。我个人习惯用它来简化复杂的类型定义。
type ID = string | number;
type Point = { x: number; y: number };
let userId: ID = "abc123";
let position: Point = { x: 10, y: 20 };
4.2 泛型:让代码更通用
泛型,说白了就是「类型参数化」。你写一个函数或类,不把类型写死,而是让调用者来决定。我刚开始学的时候觉得这玩意儿有点绕,但用多了就发现,它真的太香了。
4.2.1 泛型函数
举个例子,你想写一个函数,返回传入的数组的第一个元素。如果不使用泛型,你得为每种类型写一个重载。有了泛型,一行搞定。
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
const num = first([1, 2, 3]); // num 的类型是 number | undefined
const str = first(["a", "b"]); // str 的类型是 string | undefined
你看,T 就像一个占位符,调用时自动推断出具体类型。我在鸿蒙的多设备数据同步模块中,就用泛型写了一个通用的缓存工具,不管存什么类型的数据,都能保证类型安全。
4.2.2 泛型约束
有时候,你不能让 T 太「自由」。比如你想写一个函数,获取对象的 length 属性。但并不是所有类型都有 length。这时候就需要约束。
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(arg: T): T {
console.log(arg.length);
return arg;
}
logLength("hello"); // 5
logLength([1, 2, 3]); // 3
// logLength(123); // 报错:number 没有 length 属性
4.2.3 泛型类与泛型接口
泛型不仅可以用在函数上,类、接口也都可以。比如鸿蒙中的 ArrayList<T> 就是一个典型的泛型类。
class Stack<T> {
private items: T[] = [];
push(item: T): void {
this.items.push(item);
}
pop(): T | undefined {
return this.items.pop();
}
}
const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
console.log(numberStack.pop()); // 2
4.3 模块化编程:把代码拆开,再拼起来
模块化,说白了就是「分而治之」。一个文件只做一件事,然后通过 import 和 export 把它们串起来。鸿蒙的 ArkTS 完全支持 ES Module 标准。
4.3.1 导出与导入
你可以导出变量、函数、类、接口等。我个人习惯用命名导出,因为 IDE 的自动补全支持得更好。
// mathUtils.ts
export function add(a: number, b: number): number {
return a + b;
}
export const PI = 3.14159;
// main.ts
import { add, PI } from './mathUtils';
console.log(add(PI, 2)); // 5.14159
4.3.2 默认导出
每个模块只能有一个默认导出。我一般只在主组件或主类上使用默认导出。
// Logger.ts
export default class Logger {
log(msg: string) {
console.log(msg);
}
}
// app.ts
import Logger from './Logger';
const logger = new Logger();
logger.log("Hello");
4.3.3 模块化在鸿蒙中的实践
在鸿蒙多设备协同开发中,模块化尤其重要。比如你可以把网络请求、数据模型、UI组件分别放在不同模块中。这样,手机端和平板端可以共享数据模型和网络层,只替换 UI 层。
4.4 状态管理:让数据流动起来
状态管理,说白了就是「数据怎么存、怎么改、怎么通知 UI 更新」。在鸿蒙中,ArkTS 提供了 @State、@Prop、@Link 等装饰器来管理状态。
4.4.1 @State:组件的本地状态
@State 装饰的变量,一旦发生变化,UI 会自动重新渲染。我刚开始用的时候觉得这很神奇,后来理解了它的原理——其实就是观察者模式。
@Entry
@Component
struct Counter {
@State count: number = 0;
build() {
Column() {
Text(`计数: ${this.count}`)
.fontSize(30)
Button('增加')
.onClick(() => {
this.count++;
})
}
}
}
你看,点击按钮后 count 增加,UI 自动更新。不需要手动操作 DOM,这就是声明式编程的魅力。
4.4.2 @Prop:父子组件传值
@Prop 用于父组件向子组件传递数据。子组件可以读取,但不能修改父组件的值。
@Component
struct ChildComponent {
@Prop message: string;
build() {
Text(this.message)
.fontSize(20)
}
}
@Entry
@Component
struct ParentComponent {
build() {
ChildComponent({ message: "来自父组件的问候" })
}
}
4.4.3 @Link:双向绑定
@Link 用于父子组件之间的双向数据同步。子组件修改了数据,父组件也会同步更新。
@Component
struct ChildComponent {
@Link count: number;
build() {
Button('子组件增加')
.onClick(() => {
this.count++;
})
}
}
@Entry
@Component
struct ParentComponent {
@State count: number = 0;
build() {
Column() {
Text(`父组件计数: ${this.count}`)
ChildComponent({ count: this.count })
}
}
}
@Link 时,不小心在子组件中直接赋值(this.count = 10),导致父组件的状态被意外覆盖。记住:@Link 是引用传递,修改时要谨慎。
4.5 本章知识体系总览
为了让你更直观地理解这一章的知识结构,我画了一张图。你可以看到,高级类型、泛型、模块化和状态管理,它们之间是层层递进的关系。
这一节的内容确实不少,但都是硬核干货。高级类型让你的类型定义更灵活;泛型让你的代码更通用;模块化让你的项目结构更清晰;状态管理让你的 UI 和数据同步更简单。把这四个点吃透了,你在鸿蒙开发中就能写出更优雅、更健壮的代码。