一 类
TypeScript核心规则是要求,实例化后每个属性都有确定的值- 至于这个值从哪里来(构造函数、默认值、可选),它不管。
1.1 类的声明
js
class Person {
// 实例属性
public name: string = '' // public可以省略, 实例变量需要初始值
public subName: string = '' // public可以省略, 实例变量需要初始值
public age?: number; // number| undefined
// 构造方法
constructor (name: string, subName: string) {
this.name = name;
this.subName = subName;
}
// 实例方法 在类中声明方法,不加 function
function fullName(): string {
return this.name + ' ' + this.subName
}
}
1.2 类的初始化
js
class Point {
x: number = 0;
y: number = 0;
}
// 1 new 创建实例
let p = new Person();
// 2 字面量创建实例
let p1: Person = {x: 30, y: 20 };
1.3 静态属性
js
class Person {
public static personNumber: number = 0 // 静态变量
constructor() {
Person.personNumber ++
}
}
let num = Person.personNumber
1.4 字段初始化
js
class Person {
name?: string; // 不需要 前面家let
setName(newName: string) {
this.name = newName;
}
getName():string | undefined {
return this.name;
}
}
let n = new Person()
n.gatName()?.lenth // 编译成功
1.5 getter / setter
- 注意:arkTs 声明实例变量,不会自动生成getter/setter方法
js
class Person {
_age: number = 0;
set age(newAge: number) {
if(newAge < 0 ) {
throw Error('年龄不能小于0!')
}
this._age = newAge;
}
get age():number {
return this._age;
}
}
let jack = new Person();
jack.age = -22; // 访问get方法,非访问_age;
jack.age; // 访问get方法,非访问_age;
1.6 实例方法 静态方法
- 类中的方法,不需要添加function
js
class Person {
name: string = ''
eatChild() {
}
static eatFood() {
}
}
1.7 类继承, 接口继承
- 父类:基类
- 子类:派生类
- 继承类继承基类的字段和方法,但不继承构造函数
js
class Father {
}
class Sun extends Father {
}
js
interface DataInterface {
new(): string;
}
class myData implement DataInterface {
new(): string {
return '我实现了哈~';
}
}
1.8 构造函数,访问父类
js
class Person {
name: strinh = '';
age: number = 0;
constructior(name: string, age: number) {
this.name = name;
this.age = age;
}
}
class Son extends Person {
height: number = 0
constructor(height: number, name: string, age: number) {
super(name,age) // 调用父类
this.height = height;
}
}
1.9 可见性修饰符
| 修饰符 | 类内部 | 子类(继承) | 类外部 |
|---|---|---|---|
public 公开 |
✅ 可访问 | ✅ 可访问 | ✅ 可访问 |
protected 受保护 |
✅ 可访问 | ✅ 可访问 | ❌ 不可访问 |
private 私有 |
✅ 可访问 | ❌ 不可访问 | ❌ 不可访问 |
1.10 对象字面量
- 当创建实例为类时候,代替new表达式
- 对象字面量只能,在可以推导出该字面量类型的上下文中使用
js
class Person {
name: string = '';
age: number = 0;
}
let p:Person = {name:'jack', age: 13}; // 对象字面量,注意要加属于的类型
// 在数组中使用
let arr:Person[] = [{name: 'jack', age: 12}, {name: 'lucy', age: 11}];
1.11 Record类型 的对象字面量
- 在第一章介绍
1.12 抽象类 abstract
- interface接口:定规矩(轻量级),支持多继承
- abstract抽象方法:定规矩 + 公共代码(字段,构造函数及公共方法),单继承
抽象方法 vs 普通方法
| 对比 | 抽象方法 | 普通方法 |
|---|---|---|
| 有没有方法体 | ❌ 没有(; 结尾) |
✅ 有({ ... }) |
| 子类必须实现 | ✅ 必须重写 | ❌ 可以不重写,直接用 |
| 能不能直接调用 | ❌ 不能(没有实现) | ✅ 能 |
| 在抽象类里 | ✅ 可以 | ✅ 可以 |
| 在普通类里 | ❌ 不可以 | ✅ 可以 |
js
// 定义抽象类
abstract class Shape {
// 定义普通实例变量
color: string;
// 定义普通构造方法
constructior(color: string) {
this.color = color;
}
// 定义普通方法
showColor() {
console.log('颜色 ---- ${this.color}');
}
// 定义抽象方法, 要求子类强制实现
abstract area(): number;
}
js
// 继承抽象类
class Rect: extends Shape {
width: number = 0;
height: number = 0;
constructior(color: string, width: number, height: number) {
super(color);
this.width = width;
this.height = height;
}
area(): number {
return this.width * this.height;
}
}
二 接口 interface
- 接口支持继承,继承用
extends - 类可以遵守多个接口,遵守用
implements
js
// 定义接口
interface pro {
name: string;
eat(): void; // 协议里面,返回值类型必须写
}
// 接口支持继承
interface pro1 extends pro {
age: number;
run(): void;// 协议里面,返回值类型必须写
}
// 类可以遵守多个接口
class Person implements pro, pro1 {
name: string = '';
age: number = 0;
eat() {
console.log('吃呀,吃呀,吃一个啊~');
}
run() {
console.log('run~~');
}
}
2.1 接口 vs 抽象类
- 类多继承接口,单继承抽象类
- 接口不能有静态代码块及方法,抽象类可以
- 接口不能有方法实现,抽象类可以(定义普通方法可以有时实现)
- 接口不能有构造函数,抽象类可以
三 泛型类、接口及函数
3.1 泛型接口,泛型类
js
// 泛型接口, 泛型Element继承p1,p2接口
interface pro <Element extends p1, p2> {
num: Element;
}
class Person<Element> {
}
let p = new Person<string>();
3.2 泛型函数
js
// 返回数组最后一个元素
function lastElement<E>(array: E[]): E {
return array[array.length - 1];
}
let last = lastElement<number>([1,2,3]); // 3
四 空安全
4.1 T | null | undefined
- arkts不允许直接赋值为 null 或 undefined
- 想赋值为null / undefined,需要定义联合类型 T | null | undefined
js
let x: number | null | undefined;
x = null;
x = undefined;
4.2 !非空断言预算符
- 告诉编译器,这个值肯定不是 null/undefined,放心用,出了事我负责
js
clss A {
value: string = '';
}
function foo(a: A| null) {
a!.value; // 如果真的a为nill,则程序崩溃
}
4.3 支持空合并运算符及可选链
- 如果属性为null、undefined,则可选链返回undefined
五 模块
5.1 什么是模块
- 一个.ets文件,就是一个模块
- 还有
.ts(TypeScript),.js、.mjs、.cjs(JavaScript)``.jsx、.tsx (Rect)
5.2 静态导出
js
// 导出类
export class Person {
}
// 导出对象p
export let p = new Person()
// 导出方法
export function sum(num1: number, num2: number): number {
return num1 + num2;
}
5.3 静态导入
-
导入路径:导入的模块
-
导入绑定:把导出的所有东西打包放进包裹"A",用A.XXX拆开用
5.3.1 路径知识补充
js
./ = 当前目录
../ = 上一级目录
../../ = 上两级目录
../../../ = 上三级目录
js
entry/src/main/ets/
├── entryability/
│ └── EntryAbility.ets ← 文件1
├── pages/
│ └── Index.ets ← 文件2
// 在Index.ets 中 引入 EntryAbility.ets
../entryability/EntryAbility
js
// utils.ets - 导出各种东西
// 导出类
export class Person {
name: string = '';
age: number = 0;
constructor (name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello(name: string) {
console.log(`${this.name} say hello`)
}
}
// 导出函数
export function add(a: number, b: number): number {
return a + b;
}
// 导出常量
export const PI = 3.14159;
// 导出实例(现成的对象)
export let defPerson = new Person("默认用户", 18);
csharp
// 目录结构
project/
├── utils.ets # 导出模块
└── app.ets # 导入并使用
5.3.2 导入路径(不带前缀使用)
js
// app.ets 导入各种东西
import {Person, add, PI, defPerson} from ./utils;
let p = new Person();
add(1,2);
console.log(PI);
defPerson.sayHello('小华'); // 小华 say hello
5.3.3 全部导入(带前缀使用)
js
// app.ets 导入各种东西
import * as Untils from ./utils;//"Untils"为别名,可自定义,通过该名称调用模块的接口。
let p = new Untils.Person();
Untils.add(1,2);
console.log(Untils.PI);
Untils.defPerson.sayHello('小华'); // 小华 say hello
5.4 导入,导出(动态)'
import('./Feature')返回Promise对象
js
// ========== Feature.ts ==========
//1 单独导出变量和函数
export const FEATURE_VERSION = '2.1.0';
export function doSomething(): void {
console.log('执行了 doSomething');
}
export function calculate(a: number, b: number): number {
return a + b;
}
// 2 导出类
export class FeatureService {
private name: string;
constructor(name: string) {
this.name = name;
}
greet(): string {
return `Hello from ${this.name}`;
}
}
// 3 集中导出(统一对外暴露)
const helper = (msg: string) => console.log('Helper:', msg);
const config:Record<string,number> = { 'maxRetry': 3, 'timeout':5000 };
export { helper, config };
export { helper, config };
// 4 默认导出(模块的"主角")
// 每个模块只能有一个 export default
export default class FeatureMain {
run(): void {
console.log('FeatureMain 运行中...');
}
}
5.4.1 同步方法中,获取导入
js
// ========== Main.ets ==========
import('./Feature')
.then((module) => {
// 通过 .default 获取 export default标记的类
const MainClass = module.default;
const instance = new MainClass();
instance.run(); // 输出: FeatureMain 运行中...
// ---------- 访问具名导出 ----------
console.log(module.FEATURE_VERSION); // 输出: 2.1.0
module.doSomething(); // 输出: 执行了 doSomething
const result = module.calculate(10, 20);
console.log('计算结果:', result); // 输出: 30
// ---------- 使用导出类 ----------
const service = new module.FeatureService('ArkTS');
console.log(service.greet()); // 输出: Hello from ArkTS
// ---------- 使用集中导出的内容 ----------
module.helper('动态导入成功!'); // 输出: Helper: 动态导入成功!
console.log(module.config.maxRetry); // 输出: 3
})
.catch((err: Error) => {
console.error('模块加载失败:', err.message);
});
//
5.4.2 异步方法中,获取导入
js
async function test() {
let ns = await import('./say');// 等待 promise 对象完成
let hi = ns.hi;
let bye = ns.bye;
hi();
bye();
}
// 不加 await
// 输出: Promise { <pending> } ← 只是一个 Promise 对象,不是真正的值
// 添加 await
// 输出: { hi: [Function], bye: [Function] } ← 真正的模块对象
5.5 引入SDK
js
// 引入系统的UIKit,引入华为UI组件
import UIAbility from '@ohos.app.ability.UIAbility';
js
// 导入单接口
import { UIAbility } from '@kit.AbilityKit';
js
//导入多接口
import { UIAbility, Ability, Context } from '@kit.AbilityKit';
js
// "module"为别名,可自定义,然后通过该名称调用模块的接口。
import * as module from '@kit.AbilityKit';
六 注解
- 定义注解,通过框架,获取注解信息,实现代码封装
js
@interface API {
path: string;
method: string;
}
@API({path: 'http://123@.com',method: 'Get'})
clsss loadData {
}