第2次:ArkTS 语言基础
ArkTS 是 HarmonyOS 应用开发的主力语言,基于 TypeScript 扩展而来。本次课程将系统学习 ArkTS 的核心语法,为后续开发打下坚实基础。
学习目标
- 理解 ArkTS 与 TypeScript 的关系
- 掌握基本数据类型与变量声明
- 熟练使用函数与箭头函数
- 理解类与接口的定义方式
- 掌握泛型基础用法
- 学会模块的导入导出
2.1 ArkTS 与 TypeScript 的关系
什么是 ArkTS?
ArkTS 是华为基于 TypeScript 开发的编程语言,专为 HarmonyOS 应用开发设计。
JavaScript (动态类型)
↓ 添加类型系统
TypeScript (静态类型)
↓ 添加声明式UI、状态管理
ArkTS (HarmonyOS专用)
ArkTS 的特点
| 特性 | 说明 |
|---|---|
| 静态类型 | 编译时类型检查,减少运行时错误 |
| 声明式UI | 使用装饰器定义组件和状态 |
| 状态管理 | 内置 @State、@Prop 等装饰器 |
| 高性能 | 编译为方舟字节码,运行效率高 |
ArkTS 的限制
相比标准 TypeScript,ArkTS 有一些限制:
typescript
// ❌ 不支持 any 类型
let data: any = 123; // 错误
// ✅ 使用具体类型
let data: number = 123; // 正确
// ❌ 不支持动态属性访问
obj[dynamicKey]; // 错误
// ✅ 使用明确的属性名
obj.propertyName; // 正确
2.2 基本数据类型与变量声明
变量声明
ArkTS 使用 let 和 const 声明变量:
typescript
// let - 可变变量
let count: number = 0;
count = 10; // 可以重新赋值
// const - 常量
const PI: number = 3.14159;
// PI = 3.14; // 错误!常量不能重新赋值
// 类型推断 - 可省略类型注解
let name = '张三'; // 自动推断为 string
const age = 25; // 自动推断为 number
基本数据类型
1. 数字类型 (number)
typescript
// 整数
let count: number = 100;
// 浮点数
let price: number = 99.99;
// 十六进制
let hex: number = 0xff;
// 二进制
let binary: number = 0b1010;
// 数学运算
let sum = 10 + 20; // 30
let product = 5 * 4; // 20
let quotient = 20 / 4; // 5
let remainder = 10 % 3; // 1
2. 字符串类型 (string)
typescript
// 单引号
let name: string = '张三';
// 双引号
let title: string = "React 教程";
// 模板字符串(反引号)
let greeting: string = `你好,${name}!`;
// 字符串拼接
let fullName = '张' + '三';
// 常用方法
let str = 'Hello World';
str.length; // 11
str.toUpperCase(); // 'HELLO WORLD'
str.toLowerCase(); // 'hello world'
str.substring(0, 5); // 'Hello'
str.split(' '); // ['Hello', 'World']
str.includes('World'); // true
3. 布尔类型 (boolean)
typescript
let isActive: boolean = true;
let isCompleted: boolean = false;
// 逻辑运算
let a = true;
let b = false;
a && b; // false (与)
a || b; // true (或)
!a; // false (非)
// 比较运算
10 > 5; // true
10 < 5; // false
10 === 10; // true (严格相等)
10 !== 5; // true (严格不等)
4. 数组类型 (Array)
typescript
// 方式一:类型[]
let numbers: number[] = [1, 2, 3, 4, 5];
let names: string[] = ['张三', '李四', '王五'];
// 方式二:Array<类型>
let scores: Array<number> = [90, 85, 92];
// 数组操作
let arr = [1, 2, 3];
arr.push(4); // 添加到末尾 [1, 2, 3, 4]
arr.pop(); // 移除末尾 [1, 2, 3]
arr.unshift(0); // 添加到开头 [0, 1, 2, 3]
arr.shift(); // 移除开头 [1, 2, 3]
arr.length; // 3
arr.indexOf(2); // 1
arr.includes(2); // true
// 遍历数组
for (let item of arr) {
console.log(item);
}
arr.forEach((item, index) => {
console.log(`${index}: ${item}`);
});
// 数组变换
let doubled = arr.map(x => x * 2); // [2, 4, 6]
let filtered = arr.filter(x => x > 1); // [2, 3]
let sum = arr.reduce((a, b) => a + b, 0); // 6
5. 对象类型 (Object)
typescript
// 对象字面量
let person: object = {
name: '张三',
age: 25
};
// 更精确的类型定义
let user: { name: string; age: number } = {
name: '李四',
age: 30
};
// 访问属性
console.log(user.name); // '李四'
console.log(user.age); // 30
// 修改属性
user.age = 31;
6. 联合类型
typescript
// 变量可以是多种类型之一
let id: string | number;
id = '001'; // 正确
id = 1; // 正确
// 常用于可选值
let result: string | null = null;
result = '成功';
7. 字面量类型
typescript
// 限定变量只能是特定值
let direction: 'left' | 'right' | 'up' | 'down';
direction = 'left'; // 正确
// direction = 'top'; // 错误
// 常用于状态定义
type Status = 'pending' | 'success' | 'error';
let currentStatus: Status = 'pending';
2.3 函数与箭头函数
函数声明
typescript
// 基本函数
function greet(name: string): string {
return `你好,${name}!`;
}
// 调用函数
let message = greet('张三'); // '你好,张三!'
函数参数
typescript
// 必选参数
function add(a: number, b: number): number {
return a + b;
}
add(1, 2); // 3
// 可选参数(使用 ?)
function greet(name: string, title?: string): string {
if (title) {
return `${title} ${name},你好!`;
}
return `${name},你好!`;
}
greet('张三'); // '张三,你好!'
greet('张三', '教授'); // '教授 张三,你好!'
// 默认参数
function createUser(name: string, age: number = 18): object {
return { name, age };
}
createUser('李四'); // { name: '李四', age: 18 }
createUser('王五', 25); // { name: '王五', age: 25 }
// 剩余参数
function sum(...numbers: number[]): number {
return numbers.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4, 5); // 15
箭头函数
typescript
// 基本语法
const add = (a: number, b: number): number => {
return a + b;
};
// 简写:单表达式可省略 {} 和 return
const multiply = (a: number, b: number): number => a * b;
// 单参数可省略括号
const double = (x: number): number => x * 2;
// 无参数
const sayHello = (): void => {
console.log('Hello!');
};
// 实际应用:数组方法中的回调
let numbers = [1, 2, 3, 4, 5];
let doubled = numbers.map(n => n * 2);
let evens = numbers.filter(n => n % 2 === 0);
let sum = numbers.reduce((acc, n) => acc + n, 0);
函数类型
typescript
// 定义函数类型
type MathOperation = (a: number, b: number) => number;
// 使用函数类型
const add: MathOperation = (a, b) => a + b;
const subtract: MathOperation = (a, b) => a - b;
// 函数作为参数
function calculate(a: number, b: number, operation: MathOperation): number {
return operation(a, b);
}
calculate(10, 5, add); // 15
calculate(10, 5, subtract); // 5
2.4 类与接口定义
接口 (Interface)
接口用于定义对象的结构:
typescript
// 定义接口
interface User {
id: number;
name: string;
email: string;
age?: number; // 可选属性
}
// 使用接口
let user: User = {
id: 1,
name: '张三',
email: 'zhangsan@example.com'
};
// 接口继承
interface Admin extends User {
role: string;
permissions: string[];
}
let admin: Admin = {
id: 2,
name: '管理员',
email: 'admin@example.com',
role: 'super_admin',
permissions: ['read', 'write', 'delete']
};
类型别名 (Type)
typescript
// 基本类型别名
type ID = string | number;
type Status = 'pending' | 'success' | 'error';
// 对象类型别名
type Point = {
x: number;
y: number;
};
// 函数类型别名
type Callback = (data: string) => void;
// 使用
let userId: ID = '001';
let status: Status = 'success';
let point: Point = { x: 10, y: 20 };
Interface vs Type
typescript
// Interface - 可以被扩展和合并
interface Animal {
name: string;
}
interface Animal { // 声明合并
age: number;
}
// Animal 现在有 name 和 age
// Type - 不能重复声明,但可以用交叉类型
type Pet = {
name: string;
} & {
age: number;
};
类 (Class)
typescript
// 基本类定义
class Person {
// 属性
name: string;
age: number;
// 构造函数
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 方法
introduce(): string {
return `我是${this.name},今年${this.age}岁`;
}
}
// 创建实例
let person = new Person('张三', 25);
person.introduce(); // '我是张三,今年25岁'
访问修饰符
typescript
class User {
public name: string; // 公开,任何地方可访问
private password: string; // 私有,只能在类内部访问
protected email: string; // 受保护,类内部和子类可访问
readonly id: number; // 只读,初始化后不能修改
constructor(id: number, name: string, password: string, email: string) {
this.id = id;
this.name = name;
this.password = password;
this.email = email;
}
// 私有方法
private hashPassword(): string {
return `hashed_${this.password}`;
}
// 公开方法
public validatePassword(input: string): boolean {
return this.password === input;
}
}
类的继承
typescript
// 父类
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
speak(): void {
console.log(`${this.name} 发出声音`);
}
}
// 子类
class Dog extends Animal {
breed: string;
constructor(name: string, breed: string) {
super(name); // 调用父类构造函数
this.breed = breed;
}
// 重写父类方法
speak(): void {
console.log(`${this.name} 汪汪叫`);
}
// 子类特有方法
fetch(): void {
console.log(`${this.name} 去捡球`);
}
}
let dog = new Dog('旺财', '金毛');
dog.speak(); // '旺财 汪汪叫'
dog.fetch(); // '旺财 去捡球'
静态成员
typescript
class MathUtils {
static PI: number = 3.14159;
static add(a: number, b: number): number {
return a + b;
}
static multiply(a: number, b: number): number {
return a * b;
}
}
// 直接通过类名访问,无需实例化
MathUtils.PI; // 3.14159
MathUtils.add(1, 2); // 3
MathUtils.multiply(3, 4); // 12
2.5 泛型基础
泛型允许创建可重用的组件,支持多种类型。
泛型函数
typescript
// 不使用泛型 - 需要为每种类型写一个函数
function identityNumber(arg: number): number {
return arg;
}
function identityString(arg: string): string {
return arg;
}
// 使用泛型 - 一个函数支持所有类型
function identity<T>(arg: T): T {
return arg;
}
// 调用
identity<number>(123); // 123
identity<string>('hello'); // 'hello'
identity(true); // 类型推断为 boolean
泛型接口
typescript
// 泛型接口
interface Response<T> {
code: number;
message: string;
data: T;
}
// 使用不同类型
let userResponse: Response<{ name: string; age: number }> = {
code: 200,
message: 'success',
data: { name: '张三', age: 25 }
};
let listResponse: Response<string[]> = {
code: 200,
message: 'success',
data: ['item1', 'item2', 'item3']
};
泛型类
typescript
class Container<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
setValue(value: T): void {
this.value = value;
}
}
let numberContainer = new Container<number>(100);
numberContainer.getValue(); // 100
let stringContainer = new Container<string>('hello');
stringContainer.getValue(); // 'hello'
泛型约束
typescript
// 约束泛型必须有 length 属性
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(arg: T): number {
console.log(arg.length);
return arg.length;
}
logLength('hello'); // 5 - 字符串有 length
logLength([1, 2, 3]); // 3 - 数组有 length
// logLength(123); // 错误!number 没有 length
2.6 模块导入导出
导出 (Export)
typescript
// constants.ts
// 导出常量
export const APP_NAME = 'React Tutorial';
export const VERSION = '1.0.0';
// 导出函数
export function formatDate(date: Date): string {
return date.toISOString().split('T')[0];
}
// 导出类
export class Logger {
static log(message: string): void {
console.log(`[LOG] ${message}`);
}
}
// 导出接口
export interface Config {
apiUrl: string;
timeout: number;
}
// 默认导出(每个文件只能有一个)
export default class App {
name: string = APP_NAME;
}
导入 (Import)
typescript
// main.ts
// 导入默认导出
import App from './constants';
// 导入命名导出
import { APP_NAME, VERSION, formatDate, Logger } from './constants';
// 导入并重命名
import { APP_NAME as appName } from './constants';
// 导入所有
import * as Constants from './constants';
// 使用:Constants.APP_NAME, Constants.VERSION
// 混合导入
import App, { APP_NAME, VERSION } from './constants';
实际项目中的模块组织
typescript
// models/User.ts
export interface User {
id: number;
name: string;
email: string;
}
export const DEFAULT_USER: User = {
id: 0,
name: 'Guest',
email: ''
};
// services/UserService.ts
import { User, DEFAULT_USER } from '../models/User';
export class UserService {
private currentUser: User = DEFAULT_USER;
login(user: User): void {
this.currentUser = user;
}
logout(): void {
this.currentUser = DEFAULT_USER;
}
getCurrentUser(): User {
return this.currentUser;
}
}
// pages/Index.ts
import { UserService } from '../services/UserService';
import { User } from '../models/User';
const userService = new UserService();
2.7 实操:编写项目数据模型 Models.ets
现在,让我们为 React 学习教程 App 创建数据模型文件。
步骤 1:创建 models 目录
在 entry/src/main/ets/ 下创建 models 文件夹。
步骤 2:创建 Models.ets 文件
创建 entry/src/main/ets/models/Models.ets,输入以下代码:
typescript
/**
* 数据模型定义
* React 教程应用的所有类型接口
*/
/**
* 难度等级类型
*/
export type DifficultyType = 'beginner' | 'basic' | 'intermediate' | 'advanced' | 'ecosystem';
/**
* 代码语言类型
*/
export type CodeLanguage = 'javascript' | 'typescript' | 'jsx' | 'tsx' | 'css' | 'json' | 'bash' | 'html' | 'text';
/**
* 内容段落类型
*/
export type SectionType = 'text' | 'code' | 'tip' | 'warning' | 'note';
/**
* 徽章类别
*/
export type BadgeCategory = 'progress' | 'streak' | 'quiz' | 'project';
/**
* 学习模块
*/
export interface LearningModule {
id: string; // 模块唯一标识
title: string; // 模块标题
description: string; // 模块描述
difficulty: DifficultyType; // 难度等级
icon: string; // 图标(emoji)
color: string; // 主题色
lessonCount: number; // 课程数量
estimatedTime: string; // 预计学习时间
prerequisites: string[]; // 前置模块ID
lessons: Lesson[]; // 课程列表
}
/**
* 课程
*/
export interface Lesson {
id: string; // 课程唯一标识
moduleId: string; // 所属模块ID
title: string; // 课程标题
description: string; // 课程描述
order: number; // 排序序号
content: LessonContent; // 课程内容
hasPlayground: boolean; // 是否有代码练习
hasQuiz: boolean; // 是否有测验
}
/**
* 课程内容
*/
export interface LessonContent {
sections: ContentSection[]; // 内容段落
codeExamples: CodeExample[]; // 代码示例
tableOfContents: TOCItem[]; // 目录
keyTakeaways: string[]; // 关键要点
}
/**
* 内容段落
*/
export interface ContentSection {
id: string; // 段落ID
title: string; // 段落标题
content: string; // 段落内容
type: SectionType; // 段落类型
}
/**
* 代码示例
*/
export interface CodeExample {
id: string; // 示例ID
title: string; // 示例标题
code: string; // 代码内容
language: CodeLanguage; // 代码语言
explanation: string; // 代码解释
isEditable: boolean; // 是否可编辑
}
/**
* 目录项
*/
export interface TOCItem {
id: string; // 目录项ID
title: string; // 目录标题
level: number; // 层级(1-3)
}
/**
* 用户进度
*/
export interface UserProgress {
completedLessons: string[]; // 已完成课程ID列表
completedModules: string[]; // 已完成模块ID列表
currentLesson: string | null; // 当前学习课程ID
learningStreak: number; // 连续学习天数
lastStudyDate: string; // 最后学习日期
totalStudyTime: number; // 总学习时长(分钟)
badges: Badge[]; // 获得的徽章
}
/**
* 成就徽章
*/
export interface Badge {
id: string; // 徽章ID
name: string; // 徽章名称
description: string; // 徽章描述
icon: string; // 徽章图标
earnedDate: string; // 获得日期
category: BadgeCategory; // 徽章类别
}
/**
* 测验
*/
export interface Quiz {
id: string; // 测验ID
moduleId: string; // 所属模块ID
lessonId?: string; // 所属课程ID(可选)
title: string; // 测验标题
questions: QuizItem[]; // 题目列表
passingScore: number; // 及格分数
timeLimit?: number; // 时间限制(秒)
}
/**
* 测验题目
*/
export interface QuizItem {
id: string; // 题目ID
question: string; // 题目内容
options: string[]; // 选项列表
correctAnswer: number; // 正确答案索引
explanation: string; // 答案解析
codeSnippet?: string; // 代码片段(可选)
}
/**
* 测验结果
*/
export interface QuizResult {
quizId: string; // 测验ID
score: number; // 得分
totalQuestions: number; // 总题数
passed: boolean; // 是否通过
answers: number[]; // 用户答案
completedAt: string; // 完成时间
timeSpent: number; // 用时(秒)
}
/**
* 收藏
*/
export interface Bookmark {
lessonId: string; // 课程ID
moduleId: string; // 模块ID
addedAt: string; // 添加时间
}
/**
* 搜索结果
*/
export interface SearchResult {
type: 'module' | 'lesson'; // 结果类型
id: string; // ID
title: string; // 标题
description: string; // 描述
matchedText: string; // 匹配文本
moduleId?: string; // 模块ID
moduleTitle?: string; // 模块标题
difficulty?: DifficultyType; // 难度
}
/**
* 每日一题
*/
export interface DailyQuestion {
date: string; // 日期
question: QuizItem; // 题目
moduleId: string; // 来源模块
lessonId: string; // 来源课程
answered: boolean; // 是否已答
correct?: boolean; // 是否正确
}
/**
* 默认用户进度
*/
export const DEFAULT_USER_PROGRESS: UserProgress = {
completedLessons: [],
completedModules: [],
currentLesson: null,
learningStreak: 0,
lastStudyDate: '',
totalStudyTime: 0,
badges: []
};
步骤 3:验证代码
保存文件后,确保没有语法错误。可以在其他文件中尝试导入:
typescript
// 测试导入
import { LearningModule, UserProgress, DEFAULT_USER_PROGRESS } from '../models/Models';
// 使用类型
let progress: UserProgress = DEFAULT_USER_PROGRESS;
console.log(progress.learningStreak); // 0
本次课程小结
通过本次课程,你已经:
✅ 理解了 ArkTS 与 TypeScript 的关系和区别
✅ 掌握了基本数据类型:number、string、boolean、array、object
✅ 学会了函数定义和箭头函数的使用
✅ 理解了接口和类的定义方式
✅ 掌握了泛型的基础用法
✅ 学会了模块的导入导出
✅ 完成了项目数据模型 Models.ets 的编写
课后练习
-
扩展数据模型 :为
UserProgress添加一个favoriteModules: string[]属性 -
创建工具函数 :编写一个函数,接收
LearningModule数组,返回指定难度的模块 -
泛型练习 :创建一个泛型函数
firstElement<T>(arr: T[]): T | undefined,返回数组第一个元素
下次预告
第3次:ArkUI 声明式 UI 入门
我们将学习 ArkUI 的核心概念:
- @Component 和 @Entry 装饰器
- 基础组件:Text、Button、Image
- 容器组件:Column、Row、Stack
- 样式属性与链式调用
这些是构建用户界面的基础!