本文基于Api11
语法
静态字段
使用关键字static将字段声明为静态。静态字段属于类本身,类的所有实例共享一个静态字段。
要访问静态字段,需要使用类名:
class Person {
static numberOfPersons = 0
constructor() {
// ...
Person.numberOfPersons++;
// ...
}
}
Person.numberOfPersons;
字段初始化
为了减少运行时的错误和获得更好的执行性能,ArkTS要求所有字段在声明时或者构造函数中显式初始化。这和标准TS中的strictPropertyInitialization模式一样。
class Person {
name: string = ''
setName(n:string): void {
this.name = n;
}
// 类型为'string',不可能为"null"或者"undefined"
getName(): string {
return this.name;
}
}
如果不赋初始值,要声明可空?
class Person {
name?: string
setName(n:string): void {
this.name = n;
}
getName(): string | null | undefined{
return this.name;
}
}
箭头函数
函数可以定义为箭头函数,例如:
let sum = (x: number, y: number): number => {
return x + y;
}
箭头右边可以是函数体,也可以是单个表达式:
let sum1 = (x: number, y: number) => { return x + y; }
let sum2 = (x: number, y: number) => x + y
说一个特殊的,ArkTS中不允许用对象字面量来声明类型,比如在系统源码中看到如下代码,在实际代码编写时是不允许的:
//这个箭头函数的返回值是对象字面量,也就系统源码历史遗留这么写,业务代码中这么写IDE会报错
onScrollFrameBegin(event: (offset: number, state: ScrollState) => {
offsetRemain: number;
}): ScrollAttribute;
可选链(带?调用属性)
在访问对象属性时,如果该属性是undefined或者null,可选链运算符会返回undefined
class Person {
nick: string | null = null
spouse?: Person
constructor(nick: string) {
this.nick = nick;
this.spouse = undefined;
}
setSpouse(spouse: Person): void {
this.spouse = spouse;
}
// 返回类型必须为string | null | undefined,因为该方法可能返回null或者undefined
getSpouseNick(): string | null | undefined {
return this.spouse?.nick;
}
}
导出
可以使用关键字export导出顶层的声明。
未导出的声明名称被视为私有名称,只能在声明该名称的模块中使用。
export class Point {
x: number = 0
y: number = 0
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
export let Origin = new Point(0, 0);
export function Distance(p1: Point, p2: Point): number {
return Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
}
符号和关键字
|(联合类型)理解为‘单选’
- 描述:一个值可以是几种类型中的一种。
- 用途:用于定义一个变量可以是多个不同类型中的一种。
- 例子:
type StringOrNumber = string | number; let value: StringOrNumber; value = "hello"; // 合法 value = 123; // 合法 value = true; // 不合法
&(合并类型)理解为‘全选’
- 描述:一个值必须同时满足几个类型的要求。
- 用途:用于合并多个类型,生成一个具有所有属性的新类型。
- 例子:
注意:虽然系统源码中有上面这么写的,但目前ArkTS不支持代码中这么写,可以使用继承作为替代方案,比如:type A = { name: string; }; //系统源码中有这样声明的,但ArkTS不支持使用对象字面量声明类型 type B = { age: number; }; //系统源码中有这样声明的,但ArkTS不支持使用对象字面量声明类型 type C = A & B; //可以理解为C继承了A和B let person: C = { name: "John", age: 30 };interface Identity { id: number name: string } interface Contact { email: string phoneNumber: string } interface Employee extends Identity, Contact {}
Partial(混合类型多选)理解为‘多选’
- 描述:将某个类型的所有属性变为可选属性。
- 用途:用于创建一个新类型,使得原本必需的属性变为可选。
- 例子:
所有这些属性都可以同时存在于一个对象中;Partial 使所有属性变为可选。type MethodsHeaders = Partial<{[Key in Method as Lowercase<Key>]: AxiosHeaders;} & {common: AxiosHeaders}>;
对象字面量
对象字面量是一个表达式,可用于创建类的实例并提供一些初始值。它在某些情况下更方便,可以用来代替new表达式。
对象字面量的表示方式是:封闭在花括号{ } 中的属性名:值的列表。
class C {
n: number = 0
s: string = ''
}
let c: C = {n: 42, s: 'foo'};
ArkTS是静态类型语言,如上述示例所示,对象字面量只能在可以推导出该字面量类型的上下文中使用。其他正确的例子:
class C {
n: number = 0
s: string = ''
}
let c: C
c = {n: 42, s: 'foo'}; // 使用变量的类型
function foo(c: C) {}
foo({n: 42, s: 'foo'}); // 使用参数的类型
function bar(): C {
return {n: 42, s: 'foo'}; // 使用返回类型
}
Record类型的对象字面量
泛型Record<K, V>用于将类型(键类型)的属性映射到另一个类型(值类型)。常用对象字面量来初始化该类型的值:
let map: Record<string, number> = {
'John': 25,
'Mary': 21,
}
map['John']; // 25
类型K可以是字符串类型或数值类型,而V可以是任何类型。
interface PersonInfo {
age: number
salary: number
}
let map: Record<string, PersonInfo> = {
'John': { age: 25, salary: 10},
'Mary': { age: 21, salary: 20}
}
as 类型强转
export let contactsGroups: object[] = [
{
title: 'A',
contacts: [
new Contact('艾佳', $r('app.media.iconA')),
new Contact('安安', $r('app.media.iconB')),
new Contact('Angela', $r('app.media.iconC')),
],
key: util.generateRandomUUID(true)
} as ContactsGroup,
{
title: 'B',
contacts: [
new Contact('白叶', $r('app.media.iconD')),
new Contact('伯明', $r('app.media.iconE')),
],
key: util.generateRandomUUID(true)
} as ContactsGroup,
// ...
]
Aliases类型
Aliases类型为匿名类型(数组、函数、对象字面量或联合类型)提供名称,或为已有类型提供替代名称。
type Matrix = number[][];
type Handler = (s: string, no: number) => string;
type Predicate <T> = (x: T) => Boolean;
type NullableObject = Object | null;
泛型默认值
class SomeType {}
//泛型设置了默认值
interface Interface <T1 = SomeType> { }
class Base <T2 = SomeType> { }
//下面这俩写法一样
class Derived1 extends Base implements Interface { }
class Derived2 extends Base<SomeType> implements Interface<SomeType> { }
//泛型设置了默认值
function foo<T = number>(): T { }
//下面这俩写法一样
foo();
foo<number>();
空安全
默认情况下,ArkTS中的所有类型都是不可为空的,因此类型的值不能为空。
在下面的示例中,所有行都会导致编译时错误:
let x: number = null; // 编译时错误
let y: string = null; // 编译时错误
let z: number[] = null; // 编译时错误
可以为空值的变量定义为联合类型T | null。
let x: number | null = null;
x = 1; // ok
x = null; // ok
if (x != null) { }
非空断言运算符
后缀运算符!可用于断言其操作数为非空。
应用于空值时,运算符将抛出错误。
class C {
value: number | null = 1;
}
let y: number;
let c = new C();
y = c.value + 1; // 编译时错误:无法对可空值作做加法
y = c.value! + 1; // ok,值为2
空值合并运算符
a ?? b等价于三元运算符(a != null && a != undefined) ? a : b
class Person {
// ...
nick: string | null = null
getNick(): string {
return this.nick ?? '';
}
}
接口只有一个无名函数,可以直接当函数用
注意,系统源码中虽然有这样定义的call signature,但是在自己代码中不允许这么定义,编译器会报错 arkts-no-call-signatures
export interface AsyncCallback<T, E = void> {
(err: BusinessError<E>, data: T): void; //call signature
}
loadContent(path: string, callback: AsyncCallback<void>): void;
windowStage.loadContent(RouterUrl.SPLASH, (err, data) => {
// 函数体
});
使用API
Object.keys
- 返回对象的所有一级属性。
- 不会返回对象从其原型链上继承的属性,只返回对象自身直接定义的属性。
- 不返回嵌套对象的属性: 对于嵌套的对象属性,Object.keys只会返回最外层的属性名,不会递归到嵌套对象内部。
let obj : User = { a: 1, b: 2, c: 3 };
let keys = Object.keys(obj);
console.log(keys); // 输出: ['a', 'b', 'c']
需要注意的是,Object.keys只返回对象自身的可枚举属性,不包括继承的属性。