第三章 TypeScript基础(上):变量声明、基础数据类型、类型注解、接口与对象类型
好,咱们开始进入TypeScript的世界。说实话,我刚从JavaScript转到TypeScript时,心里是有点抵触的——「多写那么多类型,不麻烦吗?」但用了两周后,我真香了。尤其是在鸿蒙ArkUI开发中,类型系统能帮你提前发现一堆潜在问题,省下的调试时间,远比你写类型的时间多。
3.1 变量声明:let 与 const
在TypeScript里,声明变量就两个关键字:let 和 const。我个人的习惯是:能用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 = '我的应用';
避坑指南:我曾经在项目中把 null 和 undefined 混用,结果在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的基础:let 和 const 怎么选、基础数据类型有哪些、类型注解怎么写、接口怎么定义和使用。说白了,这些就是TypeScript的「地基」,地基打牢了,后面学泛型、装饰器、高级类型才会轻松。
我个人觉得,TypeScript最难的不是语法,而是「类型思维」——就是写代码时脑子里时刻想着「这个变量是什么类型」。刚开始可能会觉得麻烦,但坚持两周,你会发现代码质量明显提升,bug也少了很多。
下一章咱们继续深入,聊聊函数、数组、枚举这些更实用的东西。到时候见!