HarmonyOS APP<玩转React>开源教程二:ArkTS 语言基础

第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 使用 letconst 声明变量:

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 的编写


课后练习

  1. 扩展数据模型 :为 UserProgress 添加一个 favoriteModules: string[] 属性

  2. 创建工具函数 :编写一个函数,接收 LearningModule 数组,返回指定难度的模块

  3. 泛型练习 :创建一个泛型函数 firstElement<T>(arr: T[]): T | undefined,返回数组第一个元素


下次预告

第3次:ArkUI 声明式 UI 入门

我们将学习 ArkUI 的核心概念:

  • @Component 和 @Entry 装饰器
  • 基础组件:Text、Button、Image
  • 容器组件:Column、Row、Stack
  • 样式属性与链式调用

这些是构建用户界面的基础!

相关推荐
夫琅禾费米线2 小时前
React Hook Form + Zod:优雅构建 React 表单
前端·javascript·react.js·typescript
坐吃山猪2 小时前
React+TypeScript Agent开发规范
前端·react.js·typescript
①条咸鱼2 小时前
React 项目运用 RxJS 设置节流
react.js
HwJack202 小时前
HarmonyOS ArkUI列表性能优化实战:懒加载与缓存的艺术
缓存·性能优化·harmonyos
小雨青年2 小时前
鸿蒙 HarmonyOS 6 | 多媒体 (03) 图像处理 Image Kit 与 PixelMap 实战
图像处理·华为·harmonyos
冬奇Lab4 小时前
一天一个开源项目(第47篇):Cursor Chat Browser - 浏览和管理 Cursor AI 聊天历史的 Web 应用
人工智能·开源·资讯
从文处安6 小时前
「前端何去何从」一直写 Vue ,为何要在 AI 时代去学 React?
前端·react.js
IvorySQL6 小时前
PostgreSQL 技术日报 (3月11日)|4库合一性能提升350倍与内核新讨论
数据库·postgresql·开源