快速掌握鸿蒙开发 - ArkTS的进阶语法(下)
4.工具类型
1.类型别名
类型别名,顾名思义就是给某个类型起别名,之后就可以通过这个别名来使用类型啦
试一试:
- 使用 类型别名 保存联合类型
- 直接通过类型别名来使用这个联合类型
/*
* 联合类型语法规则:
* 作用:根据现有的数据类型来定义一个新的数据类型别名,方便编码
* 语法:type 类型别名 = 类型
*
* 注意点:
* 1. 类型别名使用的时候初始值设定要和类型别名中的类型保持一致
* */
// 1. 定义了一个类型别名Length1
type Length1 = number | string
// 2. 使用类型别名定义变量的类型即可
let w1:Length1 = '100%'// ✔️
let w2:Length1 = 100 // ✔️
// let w3:Length1 = true //❌
@Entry
@Component
struct Index {
build() {
Column() {
}
// .backgroundColor()
.height('100%')
.width('100%')
}
}
2.partial<Type>
基于传入的Type类型构造一个【新类型】,将Type的所有属性设置为可选。
type 新类型 = Partial<接口>
type 新类型 = Partial<类>
// 后续使用新类型即可
试一试:
- 定义 类,添加属性
- 通过 Partial 基于上一步定义的类,返回新类型
- 使用 新类型,确认结果
/*
*Partial<Type> 作用:可以将一个类型属性转为可选
* 语法:Partial<类型> 返回新类型 ,这个新类型使用type别名来进行接管
*
* */
interface Person {
name:string
age:number
}
// Partial<Person>本质上基于原有的Person类型创建一个新类型
type newPerson = Partial<Person>
const p:newPerson = { }
class Person {
name: string = ''
age: number = 0
friends: string[] = []
}
type ParPerson = Partial<Person>
// 因为都是可选的,可以设置为空对象
let p: ParPerson = {}
3.Required<Type>
基于传入的Type类型构造一个【新类型】,将 Type 的所有属性设置为必填
type 新类型 = Required<接口>
type 新类型 = Required<类>
// 后续使用新类型即可
试一试:
- 定义 类,添加属性,全部设置为可选
- 通过 Required 基于上一步定义的类,返回新类型
- 使用 新类型,确认是否转为必填属性
interface Person {
name?:string
age?:number
}
type newPerson = Required<Person>
class Person {
name?: string
age?: number
friends?: string[]
}
type RequiredPerson = Required<Person>
// 都是必须得属性,必须设置值
let p: Required<Person> = {
name: 'jack',
age: 10,
friends: []
}
4.Readonly<Type>
基于 Type构造一个【新类型】,并将Type 的所有属性设置为readonly
type 新类型 = Readonly<接口>
type 新类型 = Readonly<类>
// 后续使用新类型即可
试一试:
- 定义 类,添加属性
- 通过 Readonly 基于上一步定义的类,返回新类型
- 使用 新类型,确认结果
class Person {
name: string = ''
age: number = 0
}
type ReadonlyIPerson = Readonly<Person>
const p: ReadonlyIPerson = {
name: 'jack',
age: 10
}
p.name = 'rose' // 报错 属性全部变成只读
5.Record<Keys,Type>
构造一个对象类型,其属性键为Keys,属性值为Type。该实用程序可用于将一种类型的属性映射到另一种类型
@State person = {'name':'张三'} // ❌这样定义报错 -> 因为没有使用interface指定对象类型
// 如果不想定义interface,就可以直接使用Record<Key,Value>来指定对象类型即可
@State person:Record<string,string> = {'name':'张三'} // ✔️
✨✨注意:{}对象的属性名类型要对应Record<Key类型,value类型> 中的Key类型,属性值对应value类型
不用写接口直接声明变量
5.空安全
默认情况下,ArkTS中的所有类型都是不可为空的。如果要设置为空,需要进行特殊的处理,并且在获取 可能为空的值的时候也需要特殊处理
1.联合类型设置为空
let x: number = null; // 编译时错误
let y: string = null; // 编译时错误
let z: number[] = null; // 编译时错误
通过联合类型指定为空即可,使用时可能需要判断是否为空
// 通过联合类型设置为空
let x: number | null = null;
x = 1; // ok
x = null; // ok
// 取值的时候,根据需求可能需要考虑 屏蔽掉空值的情况
if (x != null) { /* do something */ }
2.非空断言运算符
后缀运算符! 可用于断言其操作数为非空。
应用于空值时,运算符将抛出错误。否则,值的类型将从T | null更改为T:
let x: number | null = 1;
let y: number
y = x + 1; // 编译时错误:无法对可空值作加法
y = x! + 1; // 通过非空断言,告诉编译器 x不为 null
3.空值合并运算符
空值合并二元运算符?? 用于检查左侧表达式的求值是否等于null。如果是,则表达式的结果为右侧表达式;否则,结果为左侧表达式。
换句话说,a ?? b等价于三元运算符a != null ? a : b。
在以下示例中,getNick方法如果设置了昵称,则返回昵称;否则,返回空字符串:
class Person {
name: string | null = null
getName(): string {
// return this.name === null ? '' : this.name
// 等同于 如果 name不为空 就返回 name 反之返回 ''
return this.name ?? ''
}
}
4.可选链
在访问对象属性时,如果该属性是undefined或者null,可选链运算符会返回undefined。
(可选链?当前面的对象不为空或undefined才调用属性或方法)
class Dog {
bark() {
console.log('啊呜~')
}
}
class Person {
name?: string
dog?: Dog
constructor(name: string, dog?: Dog) {
this.name = name
this.dog = dog
}
}
const p: Person = new Person('jack')
// p.dog.bark()// 报错 dog 可能为空
// 逻辑判断
if (p.dog) {
p.dog.bark()
}
// 当 dog不为null 或 undefined 时 再调用 bark 并且不会报错
p.dog?.bark()
6.模块化
- 把一个大的程序拆分成【互相依赖】的若干小文件
- 这些小文件还可以通过【特定的语法】组合到一起
- 这个过程称之为【模块化】
优点:
1.更好维护
2.更好的复用性
缺点:
需要学习模块化语法
分析:
- 功能写完只有10行代码,模块化没啥必要!
- 功能写完有100行,或者1000行代码,里面有【好几段逻辑】在其他地方也要用--模块化
1.默认导入与导出
ArkTS 中每个 ets 文件都可以看做是一个模块,默认只能在当前文件中使用,如果要在其他位置中使用就需要:
- 当前模块中 导出模块
- 需要使用的地方 导入模块
// 默认导出
export default 需要导出的内容
// 默认导入
import xxx from '模块路径'
//试一试
// Model.ets
// 一起写
export default class Person {
name: string = ''
}
// 分开写
// export default Person
// 只能有一个默认导出
// TestModel.ets
import Person from './model'
const p: Person = new Person()
路径
/ 表示进入某个文件夹里面
. 表示当前文件所在文件夹 ./
.. 表示当前文件的上一级文件夹 ../
2.按需导入与导出
如果有很多的东西需要导出,可以使用按需导出,他也有配套的导入语法
// ---------- Model.ets ----------
const info: string = '信息'
// 单独写
export const num: number = 10
function sayHi() {
console.log('你好吗~')
}
// 或者 写到 {} 内部
export {
info, sayHi
}
// ---------- MainFile.ets ----------
import { info, num, sayHi as sayHello } from './Model'
console.log('info:', info)
// 起别名
sayHello()
console.log('num:', num + '')
3.全部导入
导出部分不需要调整,调整导入的语法即可
import * as Utils from './utils'
// 通过 Utils 即可获取 utils模块中导出的所有内容
7.定时器
日常开发中如果需要代码 延迟一会执行,或者每隔一段时间执行一次,就可以使用定时器
定时器有两种:
- setTimeout: 延迟执行
- setInterval: 间隔执行
1.setTimeout(延迟执行)
setTimeout可以用来设置一个定时器,当设置的时间到了之后就会去执行指定的函数
执行一次用 setTimeout
setTimeout、clearTimeout是一个全局函数,可以直接使用
@Entry
@Component
struct Page01_timeoutAndInterval {
timeId?: number
build() {
Column({ space: 20 }) {
Text('延时器-Timeout')
.fontSize(30)
.width('100%')
.textAlign(TextAlign.Center)
Row({ space: 20 }) {
Button('开启延时器')
.onClick(() => {
// 开启延时器
let timeId = setTimeout(() => {
// 延迟执行逻辑
console.log('代码执行啦')
}, 2000)
// 保存定时器 id
this.timeId = timeId
})
Button('关闭延时器')
.onClick(() => {
// 调用 clearTimeout 清除定时器
clearTimeout(this.timeId)
})
}
}
.padding(10)
}
}
2.setInterval(间隔执行)
setInterval 也是可以用来设置一个定时器,根据设置的时间间隔来执行指定的函数
执行多次用 setInterval!!
setInterval、clearInterval是一个全局函数,可以直接使用
// 1. 基本使用
setInterval(()=>{
// 延迟执行的逻辑
},时间)
// 2. 获取返回的定时器 id
const timeId = setInterval(()=>{
// 延迟执行的逻辑
},时间)
// 3. 根据定时器 id 清除定时器
clearInterval(timeId)
//试一试
@Entry
@Component
struct Page02_interval{
// 只是用来保存数据,不影响 UI 可以不加状态修饰符
timeId?: number
build() {
Column({ space: 20 }) {
Text('定时器-Interval')
.fontSize(30)
.width('100%')
.textAlign(TextAlign.Center)
Row({ space: 20 }) {
Button('开启延时器')
.onClick(() => {
this.timeId = setInterval(() => {
console.log('代码执行啦~')
}, 2000)
})
Button('关闭延时器')
.onClick(() => {
clearInterval(this.timeId)
})
}
}
.padding(10)
}
}更多推荐


所有评论(0)