本文记录学习ArkTS语法的欠缺知识。高级编程语言的学习是共通的。
ArkTS语法介绍
目录
- 类
- 接口
- 泛型类型和函数
- 空安全
- 模块
类
如果未定义构造函数,则会自动创建具有空参数列表的默认构造函数。
可见性修饰符:private
、protected
和 public
继承类继承基类的字段和方法,但不继承构造函数。继承类可以新增定义字段和方法,也可以覆盖其基类定义的方法。基类也称为“父类”或“超类”。继承类也称为“派生类”或“子类”。
class Person {name: string = ''private _age = 0get age(): number {return this._age;}
}class Employee extends Person {salary: number = 0calculateTaxes(): number {return this.salary * 0.42;}
}/* implements */
interface DateInterface {now(): string;
}
// 包含implements子句的类必须实现列出的接口中定义的**所有方法**,但使用默认实现定义的方法除外。
class MyDate implements DateInterface {now(): string {// 在此实现return 'now is now';}
}
方法重载签名:通过重载签名,指定方法的不同调用。具体方法为,为同一个方法写入多个同名但签名不同的方法头,方法实现紧随其后。
class C {foo(x: number): void; /* 第一个签名 */foo(x: string): void; /* 第二个签名 */foo(x: number | string): void { /* 实现签名 */}
}let c = new C();
c.foo(123); // OK,使用第一个签名
c.foo('aa'); // OK,使用第二个签名/* 构造函数重载签名 */
class C {constructor(x: number) /* 第一个签名 */constructor(x: string) /* 第二个签名 */constructor(x: number | string) { /* 实现签名 */}
}
let c1 = new C(123); // OK,使用第一个签名
let c2 = new C('abc'); // OK,使用第二个签名
对象字面量,可以用来代替new表达式。let c: C = {n: 42, s: 'foo'};
Record<K, V>
类型的对象字面量
// 键值对
let map: Record<string, number> = {'John': 25,'Mary': 21,
}map['John']; // 25// 类型K可以是字符串类型或数值类型,而V可以是任何类型。
interface PersonInfo {age: numbersalary: number
}
let map: Record<string, PersonInfo> = {'John': { age: 25, salary: 10},'Mary': { age: 21, salary: 20}
}
接口
interface
关键字
// 接口:
interface AreaSize {calculateAreaSize(): number // 方法的声明someMethod(): void; // 方法的声明
}// 实现:
class RectangleSize implements AreaSize {private width: number = 0private height: number = 0someMethod(): void {console.log('someMethod called');}calculateAreaSize(): number {this.someMethod(); // 调用另一个方法并返回结果return this.width * this.height;}
}
接口继承:包含被继承接口的所有属性和方法,还可以添加自己的属性和方法。
interface Style {color: string
}interface ExtendedStyle extends Style {width: number
}
泛型类型和函数
// 如果需要为任何数组定义相同的函数,使用类型参数将该函数定义为泛型:
function last<T>(x: T[]): T {return x[x.length - 1];
}// 显式设置的类型实参
last<string>(['aa', 'bb']);
last<number>([1, 2, 3]);// 隐式设置的类型实参
// 编译器根据调用参数的类型来确定类型实参
last([1, 2, 3]);
泛型默认值
class SomeType {}
interface Interface <T1 = SomeType> { }
class Base <T2 = SomeType> { }
class Derived1 extends Base implements Interface { }
// Derived1在语义上等价于Derived2
class Derived2 extends Base<SomeType> implements Interface<SomeType> { }function foo<T = number>(): T {// ...
}
foo();
// 此函数在语义上等价于下面的调用
foo<number>();
空安全
后缀运算符!可用于断言其操作数为非空。
class C {value: number | null = 1;
}let c = new C();
let y: number;
y = c.value + 1; // 编译时错误:无法对可空值作做加法
y = c.value! + 1; // ok,值为2
模块
动态导入:import()
语法通常称为动态导入dynamic import
,是一种类似函数的表达式,用来动态导入模块。以这种方式调用,将返回一个promise
。如下例所示,import(modulePath)
可以加载模块并返回一个promise
,该promise resolve
为一个包含其所有导出的模块对象。该表达式可以在代码中的任意位置调用。
let modulePath = prompt("Which module to load?");
import(modulePath)
.then(obj => <module object>)
.catch(err => <loading error, e.g. if no such module>)
如果在异步函数中,可以使用let module = await import(modulePath)
。
// 那么,可以像下面这样进行动态导入:
async function test() {let ns = await import('./say');let hi = ns.hi;let bye = ns.bye;hi();bye();
}