第二章:TypeScript核心语法速通

好,咱们直接进入正题。TypeScript 说白了就是给 JavaScript 穿了一层盔甲。你在鸿蒙开发里写 ArkTS,本质上就是在写 TypeScript 的超集。所以这一章,我把最常用的几个语法点给你捋一遍。

2.1 变量声明:let 和 const

我个人习惯,能用 const 的地方绝不用 let。为什么?因为代码里变量越少变化,你脑子要记的东西就越少。

// 这样写,我心里踏实
const maxRetryCount = 3;
const apiBaseUrl = 'https://api.example.com';

// 只有明确需要改变的值,才用 let
let currentPage = 1;
let timerId: number | null = null;

我在项目中遇到过一个问题:有人用 var 声明了一个循环变量,结果回调里拿到的全是最后一个值。嗯,这就是 var 的函数作用域在捣鬼。let 和 const 是块级作用域,完美避坑。

⚠️ 注意: 在 ArkTS 里,var 已经被标记为废弃。你写 var 编译器会报 warning。所以,忘掉 var 吧。

2.2 基础类型:number / string / boolean

这三个类型是基本功。你想想看,鸿蒙应用里哪个页面能离开它们?

// 数字:整数、浮点数、NaN、Infinity 都归它管
const price: number = 29.9;
const count: number = 100;

// 字符串:单引号双引号都行,我习惯用单引号
const userName: string = '张三';
const greeting: string = `你好,${userName}!`;  // 模板字符串真香

// 布尔值:true / false
const isLogin: boolean = false;
const isVIP: boolean = true;

我曾经踩过一个坑:从接口拿到的数据,明明应该是数字,结果因为 JSON 解析问题变成了字符串。然后我用 === 比较死活不相等。所以现在我对类型转换特别敏感。

💡 小技巧:Number()parseInt() 做显式转换,别依赖隐式转换。隐式转换有时候像开盲盒。

2.3 数组:Array

数组在鸿蒙开发里太常用了。列表数据、表单选项、缓存队列……到处都是它。

// 两种写法,我推荐第一种
const fruits: string[] = ['苹果', '香蕉', '橘子'];
const numbers: Array<number> = [1, 2, 3];  // 泛型写法,也行

// 只读数组:防止意外修改
const readonlyList: readonly string[] = ['a', 'b', 'c'];
// readonlyList.push('d');  // 这行会报错,编译器不让你改

为什么要有只读数组?我在项目里遇到过同事不小心 push 了一个不该 push 的数据,导致列表渲染错乱。从那以后,只要是不该变的数组,我都加上 readonly

2.4 枚举:enum

枚举这东西,说白了就是给一组常量起个有意义的名称。你写代码的时候不用记数字,记名字就行。

// 数字枚举:默认从 0 开始
enum Status {
  Pending,    // 0
  Processing, // 1
  Completed,  // 2
  Failed      // 3
}

// 字符串枚举:每个值都要手动赋值
enum HttpMethod {
  GET = 'GET',
  POST = 'POST',
  PUT = 'PUT',
  DELETE = 'DELETE'
}

// 使用
const currentStatus: Status = Status.Processing;
console.log(currentStatus);  // 输出 1

我个人习惯用字符串枚举。为什么?因为调试的时候打印出来是 'GET' 而不是 0,一眼就能看懂。数字枚举在日志里看到 0、1、2,你还得回去翻定义,多麻烦。

📌 核心要点: 枚举在编译后是真实存在的对象,不像普通类型会被擦除。所以如果你需要运行时检查值,枚举是好选择。

2.5 函数定义与箭头函数

函数是 TypeScript 的核心。鸿蒙里你写的每个页面组件、每个事件处理,本质上都是函数。

2.5.1 普通函数

// 有返回值
function add(a: number, b: number): number {
  return a + b;
}

// 无返回值:用 void
function logMessage(msg: string): void {
  console.log(msg);
  // 没有 return
}

// 可选参数:用 ?
function greet(name: string, greeting?: string): string {
  return `${greeting || '你好'},${name}`;
}

可选参数要注意:它必须放在必选参数后面。这是 TypeScript 的规则,也是常识——你想想看,如果可选参数在前面,调用的时候编译器怎么知道哪个参数被跳过了?

2.5.2 箭头函数

箭头函数我太喜欢了。它简洁,而且没有自己的 this。这在鸿蒙的组件回调里特别有用。

// 基本写法
const double = (x: number): number => x * 2;

// 多行函数体需要花括号和 return
const processData = (data: string[]): string[] => {
  const result = data.filter(item => item.length > 0);
  return result.map(item => item.trim());
};

// 在数组方法里用箭头函数,真香
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter(n => n % 2 === 0);
// 结果:[2, 4]

我曾经在项目里看到有人把箭头函数和普通函数混着用,结果 this 指向乱成一锅粥。我的建议是:在类的方法里用普通函数,在回调、数组方法、事件处理里统一用箭头函数。这样最不容易出错。

💡 避坑指南: 箭头函数不能用作构造函数。如果你写了 new myArrowFunc(),TypeScript 会直接报错。嗯,这是设计如此,箭头函数天生就不是干这个的。

2.6 类型推断与类型注解

TypeScript 很聪明,很多时候你不用写类型,它能自己推断出来。

// 类型推断:TypeScript 知道 name 是 string
const name = '鸿蒙开发';
// 等价于:const name: string = '鸿蒙开发';

// 复杂情况还是写注解更安全
function fetchData(): Promise<UserInfo> {
  // 这里显式声明返回类型,调用方一目了然
  return api.get('/user');
}

我个人习惯:简单变量靠推断,函数参数和返回值一定写注解。为什么?因为函数是代码的接口,接口清晰了,整个项目才不会乱。

2.7 小结

这一章的内容,说白了就是 TypeScript 的「最小可用集」。你掌握了 let/const、基础类型、数组、枚举、函数和箭头函数,就已经能写大部分鸿蒙页面了。

下一章我们会深入接口和类型别名,那才是 TypeScript 真正发力的地方。到时候你会看到,类型系统能帮你省多少 bug。