第三章 TypeScript基础(上):变量声明、基础数据类型、类型注解、接口与对象类型

好,咱们开始进入TypeScript的世界。说实话,我刚从JavaScript转到TypeScript时,心里是有点抵触的——「多写那么多类型,不麻烦吗?」但用了两周后,我真香了。尤其是在鸿蒙ArkUI开发中,类型系统能帮你提前发现一堆潜在问题,省下的调试时间,远比你写类型的时间多。

3.1 变量声明:let 与 const

在TypeScript里,声明变量就两个关键字:letconst。我个人的习惯是:能用const就不用let。为什么?因为不变的东西更安全,你想想看,一个变量从头到尾都不变,你就不用担心它被意外修改。

核心区别:

  • let:声明一个可变的变量,值可以重新赋值
  • const:声明一个常量,一旦赋值就不能再改
// 用 let 声明
let count = 0;
count = 1;  // 没问题

// 用 const 声明
const maxCount = 100;
maxCount = 200;  // ❌ 报错!常量不可修改

我的小技巧:在ArkUI开发中,组件的状态变量用 let,配置项、固定尺寸、颜色值这些用 const。比如 const padding = 12,这样后面改样式时一目了然。

3.2 基础数据类型

TypeScript的基础类型,说白了就是给JavaScript的值加了个「标签」。我刚开始学的时候,觉得这些类型太基础了,但后来在项目中吃过亏——有一次把一个字符串当数字传给了计算函数,结果页面直接崩了。嗯,从那以后我再也不敢轻视类型了。

常用的基础类型有这些:

类型 说明 示例
number 数字,包括整数和浮点数 let age: number = 25
string 字符串 let name: string = '张三'
boolean 布尔值,true 或 false let isActive: boolean = true
null 空值 let data: null = null
undefined 未定义 let value: undefined = undefined
void 函数没有返回值时使用 function log(): void {}
// 实际开发中的写法
let userName: string = '鸿蒙开发者';
let userAge: number = 28;
let isVip: boolean = false;

// 我习惯这样写——类型写在变量名后面,读起来很自然
const appVersion: number = 1.0;
const appName: string = '我的应用';

避坑指南:我曾经在项目中把 nullundefined 混用,结果在ArkUI的 @State 装饰器里出了奇怪的bug。记住:null 是主动赋值的空,undefined 是未赋值的空,两者不一样。

3.3 类型注解

类型注解,说白了就是告诉TypeScript「这个变量是什么类型」。你可能会问:「不写行不行?」行,但TypeScript会自己推断。不过我个人建议:写清楚类型注解,代码可读性会好很多

// 显式类型注解
let message: string = 'Hello ArkUI';

// 类型推断(不写注解,TypeScript自己猜)
let anotherMessage = 'Hello ArkUI';  // 自动推断为 string 类型

// 函数参数和返回值的类型注解
function greet(name: string): string {
  return `你好,${name}!`;
}

我的经验:在ArkUI开发中,组件的属性、状态变量、事件处理函数的参数,我建议都加上类型注解。这样别人看你的代码,一眼就知道每个变量是干嘛的。我曾经接手过一个没有类型注解的项目,光猜类型就花了两天……

3.4 接口与对象类型

接口(Interface)是TypeScript里我最喜欢的功能之一。它就像一张「蓝图」,告诉你一个对象应该长什么样。在鸿蒙开发中,接口用得特别多——定义数据模型、组件属性、API返回值,都离不开它。

// 定义一个用户接口
interface User {
  id: number;
  name: string;
  age: number;
  email?: string;  // 可选属性,用 ? 表示
  readonly createdAt: Date;  // 只读属性,初始化后不能修改
}

// 使用接口
const user: User = {
  id: 1,
  name: '李四',
  age: 30,
  email: 'lisi@example.com',
  createdAt: new Date()
};

// 可选属性可以不传
const guest: User = {
  id: 2,
  name: '游客',
  age: 0,
  createdAt: new Date()
};

你想想看,如果没有接口,你写一个函数接收对象参数时,是不是得在注释里写「这个对象要有id、name、age……」?有了接口,直接写 user: User,清晰明了。

接口的扩展:接口可以继承,就像类一样。这在大型项目中特别有用。

// 基础接口
interface BaseEntity {
  id: number;
  createdAt: Date;
}

// 扩展接口
interface Product extends BaseEntity {
  name: string;
  price: number;
  stock: number;
}

// 现在 Product 有 id、createdAt、name、price、stock 五个属性
const product: Product = {
  id: 101,
  createdAt: new Date(),
  name: '鸿蒙开发板',
  price: 299,
  stock: 50
};

避坑指南:我曾经在项目中定义了一个接口,里面有个属性忘了加 ?,结果后端返回的数据里这个字段有时会缺失,导致页面渲染报错。记住:不确定是否存在的字段,一定要用可选属性

3.5 实际应用:在ArkUI中定义组件属性

好了,理论说完了,咱们看看在ArkUI里怎么用。假设你要做一个用户卡片组件,需要接收用户数据:

// 定义用户卡片的数据接口
interface UserCardData {
  avatar: string;
  nickname: string;
  level: number;
  isOnline: boolean;
  signature?: string;  // 个性签名,可选
}

// 在组件中使用
@Component
struct UserCard {
  @Prop userData: UserCardData;

  build() {
    Column() {
      Image(this.userData.avatar)
        .width(60)
        .height(60)
        .borderRadius(30)
      Text(this.userData.nickname)
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
      Text(`Lv.${this.userData.level}`)
        .fontSize(14)
        .fontColor('#666')
      if (this.userData.signature) {
        Text(this.userData.signature)
          .fontSize(12)
          .fontColor('#999')
      }
    }
  }
}

你看,有了接口 UserCardData,这个组件需要什么数据一目了然。而且如果你传错了类型,TypeScript会在编译时就报错,而不是等到运行时才发现。

我的习惯:在ArkUI项目中,我会把所有的接口定义放在一个 types.ts 文件里,统一管理。这样不管是组件、页面还是API调用,都用同一套类型定义,避免重复和冲突。

3.6 本章小结

这一章咱们聊了TypeScript的基础:letconst 怎么选、基础数据类型有哪些、类型注解怎么写、接口怎么定义和使用。说白了,这些就是TypeScript的「地基」,地基打牢了,后面学泛型、装饰器、高级类型才会轻松。

我个人觉得,TypeScript最难的不是语法,而是「类型思维」——就是写代码时脑子里时刻想着「这个变量是什么类型」。刚开始可能会觉得麻烦,但坚持两周,你会发现代码质量明显提升,bug也少了很多。

下一章咱们继续深入,聊聊函数、数组、枚举这些更实用的东西。到时候见!