接口
接口聲明引入新類型。接口是定義代碼協(xié)定的常見方式。
任何一個(gè)類的實(shí)例只要實(shí)現(xiàn)了特定接口,就可以通過該接口實(shí)現(xiàn)多態(tài)。
接口通常包含屬性和方法的聲明
interface Style {
color: string // 屬性
}
interface AreaSize {
calculateAreaSize(): number // 方法的聲明
someMethod(): void; // 方法的聲明
}
實(shí)現(xiàn)接口的類示例:
// 接口:
interface AreaSize {
calculateAreaSize(): number // 方法的聲明
someMethod(): void; // 方法的聲明
}
// 實(shí)現(xiàn):
class RectangleSize implements AreaSize {
private width: number = 0
private height: number = 0
someMethod(): void {
console.log('someMethod called');
}
calculateAreaSize(): number {
this.someMethod(); // 調(diào)用另一個(gè)方法并返回結(jié)果
return this.width * this.height;
}
}
- 接口屬性
接口屬性可以是字段、getter、setter或getter和setter組合的形式。
屬性字段只是getter/setter對(duì)的便捷寫法。以下表達(dá)方式是等價(jià)的:
interface Style {
color: string
}
interface Style {
get color(): string
set color(x: string)
}
實(shí)現(xiàn)接口的類也可以使用以下兩種方式:
interface Style {
color: string
}
class StyledRectangle implements Style {
color: string = ''
}
interface Style {
color: string
}
class StyledRectangle implements Style {
private _color: string = ''
get color(): string { return this._color; }
set color(x: string) { this._color = x; }
}
- 接口繼承
接口可以繼承其他接口,如下面的示例所示:
interface Style {
color: string
}
interface ExtendedStyle extends Style {
width: number
}
繼承接口包含被繼承接口的所有屬性和方法,還可以添加自己的屬性和方法。
</br>
</br>
</br>
泛型類和接口
- 類和接口可以定義為泛型,將參數(shù)添加到類型定義中,如以下示例中的類型參數(shù)Element:
class CustomStack<Element> {
public push(e: Element):void {
// ...
}
}
- 要使用類型CustomStack,必須為每個(gè)類型參數(shù)指定類型實(shí)參:
let s = new CustomStack<string>();
s.push('hello');
- 編譯器在使用泛型類型和函數(shù)時(shí)會(huì)確保類型安全。參見以下示例:
let s = new CustomStack<string>();
s.push(55); // 將會(huì)產(chǎn)生編譯時(shí)錯(cuò)誤
- 泛型約束
泛型類型的類型參數(shù)可以被限制只能取某些特定的值。例如,MyHashMap<Key, Value>這個(gè)類中的Key類型參數(shù)必須具有hash方法。
interface Hashable {
hash(): number
}
class MyHashMap<Key extends Hashable, Value> {
public set(k: Key, v: Value) {
let h = k.hash();
// ...其他代碼...
}
}
- 泛型函數(shù)
使用泛型函數(shù)可編寫更通用的代碼。比如返回?cái)?shù)組最后一個(gè)元素的函數(shù):
function last(x: number[]): number {
return x[x.length - 1];
}
last([1, 2, 3]); // 3
如果需要為任何數(shù)組定義相同的函數(shù),使用類型參數(shù)將該函數(shù)定義為泛型:
function last<T>(x: T[]): T {
return x[x.length - 1];
}
現(xiàn)在,該函數(shù)可以與任何數(shù)組一起使用。
在函數(shù)調(diào)用中,類型實(shí)參可以顯式或隱式設(shè)置:
// 顯式設(shè)置的類型實(shí)參
last<string>(['aa', 'bb']);
last<number>([1, 2, 3]);
// 隱式設(shè)置的類型實(shí)參
// 編譯器根據(jù)調(diào)用參數(shù)的類型來確定類型實(shí)參
last([1, 2, 3]);
- 泛型默認(rèn)值
泛型類型的類型參數(shù)可以設(shè)置默認(rèn)值。這樣可以不指定實(shí)際的類型實(shí)參,而只使用泛型類型名稱。下面的示例展示了類和函數(shù)的這一點(diǎn)。
class SomeType {}
interface Interface <T1 = SomeType> { }
class Base <T2 = SomeType> { }
class Derived1 extends Base implements Interface { }
// Derived1在語義上等價(jià)于Derived2
class Derived2 extends Base<SomeType> implements Interface<SomeType> { }
function foo<T = number>(): T {
// ...
}
foo();
// 此函數(shù)在語義上等價(jià)于下面的調(diào)用
foo<number>();
空安全
默認(rèn)情況下,ArkTS中的所有類型都是不可為空的,因此類型的值不能為空。這類似于TypeScript的嚴(yán)格空值檢查模式(strictNullChecks),但規(guī)則更嚴(yán)格。
在下面的示例中,所有行都會(huì)導(dǎo)致編譯時(shí)錯(cuò)誤:
let x: number = null; // 編譯時(shí)錯(cuò)誤
let y: string = null; // 編譯時(shí)錯(cuò)誤
let z: number[] = null; // 編譯時(shí)錯(cuò)誤
可以為空值的變量定義為聯(lián)合類型T | null。
let x: number | null = null;
x = 1; // ok
x = null; // ok
if (x != null) { /* do something */ }
- 非空斷言運(yùn)算符
后綴運(yùn)算符!可用于斷言其操作數(shù)為非空。
應(yīng)用于可空類型的值時(shí),它的編譯時(shí)類型變?yōu)榉强疹愋汀@?,類型將從T | null更改為T:
class A {
value: number = 0;
}
function foo(a: A | null) {
a.value; // 編譯時(shí)錯(cuò)誤:無法訪問可空值的屬性
a!.value; // 編譯通過,如果運(yùn)行時(shí)a的值非空,可以訪問到a的屬性;如果運(yùn)行時(shí)a的值為空,則發(fā)生運(yùn)行時(shí)異常
}
- 空值合并運(yùn)算符
空值合并二元運(yùn)算符??用于檢查左側(cè)表達(dá)式的求值是否等于null或者undefined。如果是,則表達(dá)式的結(jié)果為右側(cè)表達(dá)式;否則,結(jié)果為左側(cè)表達(dá)式。
換句話說,a ?? b等價(jià)于三元運(yùn)算符(a != null && a != undefined) ? a : b。
在以下示例中,getNick方法如果設(shè)置了昵稱,則返回昵稱;否則,返回空字符串:
class Person {
// ...
nick: string | null = null
getNick(): string {
return this.nick ?? '';
}
}
- 可選鏈
在訪問對(duì)象屬性時(shí),如果該屬性是undefined或者null,可選鏈運(yùn)算符會(huì)返回undefined。
class Person {
nick: string | null = null
spouse?: Person
setSpouse(spouse: Person): void {
this.spouse = spouse;
}
getSpouseNick(): string | null | undefined {
return this.spouse?.nick;
}
constructor(nick: string) {
this.nick = nick;
this.spouse = undefined;
}
}
說明:getSpouseNick的返回類型必須為string | null | undefined,因?yàn)樵摲椒赡芊祷豱ull或者undefined。
可選鏈可以任意長,可以包含任意數(shù)量的?.運(yùn)算符。
在以下示例中,如果一個(gè)Person的實(shí)例有不為空的spouse屬性,且spouse有不為空的nick屬性,則輸出spouse.nick。否則,輸出undefined:
說明:getSpouseNick的返回類型必須為string | null | undefined,因?yàn)樵摲椒赡芊祷豱ull或者undefined。
可選鏈可以任意長,可以包含任意數(shù)量的?.運(yùn)算符。
在以下示例中,如果一個(gè)Person的實(shí)例有不為空的spouse屬性,且spouse有不為空的nick屬性,則輸出spouse.nick。否則,輸出undefined: