天天看點

TypeScript筆記(2)元組字元串字面量類型和枚舉類型類

元組

在TypeScript中,有元組的概念,這個概念的js實作是數組,是以可以了解為是有不同類型對象的數組。

let a:[number,string];
a = [55,'25']
           

這樣是元組的基本用法,有基本用法,那就一定有奇怪的用法。

我們可以通過一定方法對任意一個進行指派,而不管另一個

let a:[number,string];
a[1] = '25'
           

但是我們不可以在對a直接指派的時候,給出不符合規則的值

let a:[number,string] = 55;
           

這樣是無法通過編譯的。

既然是數組了,那麼可不可以繼續添加對象進去呢?當然是可以的,但是需要是規定的類型才行,比如上面我們規定元組的第一個元素是number類型,第二個是string類型,那麼後續的隻能是number、string或者他們的子類型。

字元串字面量類型和枚舉類型

這兩個為什麼要放到一起說呢?因為他們都限定了在這個類型内,可以選擇的字元串隻有有限個,是以兩個放到一起說一下。

字元串字面量類型

這個類型特别簡單,就是在自己設定的類型中,隻有有自己設定的值。

type Name = 'xiaoming' | 'xiaohong' | 'xiaoliang';
function call(name: Name){
    //call
}

call('xiaoming'); //可以編譯
call('wo'); //不能編譯
           

這就是字元串字面量類型,沒有任何變化。

枚舉

枚舉類型被用于取值限定在一定範圍内的場景,用途類似上面的字元串字面量類型。

enum Week {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

console.log(Days["Sun"] === 0); // true
console.log(Days[0] === "Sun"); // true
           

這樣就是一個枚舉類型了,他在js的實作是

var Week;
(function (Week) {
    Week[Week["Sun"] = 0] = "Sun";
    Week[Week["Mon"] = 1] = "Mon";
    Week[Week["Tue"] = 2] = "Tue";
    Week[Week["Wed"] = 3] = "Wed";
    Week[Week["Thu"] = 4] = "Thu";
    Week[Week["Fri"] = 5] = "Fri";
    Week[Week["Sat"] = 6] = "Sat";
})(Week || (Week = {}));
           

這個實作沒什麼好說的,看一眼應該就知道他的原理是怎麼回事了,如果覺得有點抽象,可以再浏覽器裡列印一下Week這個對象,就明白這裡的枚舉類型是什麼意思了。

枚舉類型還可以手動指派

enum Week {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};
console.log(Days["Sun"] === 7); // true
console.log(Days["Tue"] === 2); // true
           

枚舉類型的需要會按照以最後一個設定值為基礎,每一個值+1的順序往下排,即使最後一個設定值不為整數也是一樣。

還可以用斷言添加非數值的序數,但是這個斷言後面的所有序數都要手動設定了。

enum Days {Sun = 7, Mon, Tue, Wed, Thu, Fri, Sat = <any>"a"};
           

除了固定值的序号,還可以用計算量做需要,但是計算量和字元串序号一樣,後面都不能有未設定序号了。

在es6之前,JavaScript沒有類的概念,但是在es6中,出現了類,同樣TypeScript中也有對類的規定,這裡的規定很像java中類的規則。

修飾符

TypeScript中有三個修飾符,分别是public,private,protected。

public是公開的,可任意通路的,

private是私有的,隻能在類内部通路,他的子類和外部是不能通路的。

protected是受保護的,同樣不能再外部通路,但是可以再子類和内部通路。

class Animal {
    public name;
    public constructor(name) {
        this.name = name;
    }
}
let a = new Animal('Cat');
console.log(a.name); // Cat
           

這樣的通路是沒有問題的

class Animal {
    private name;
    public constructor(name) {
        this.name = name;
    }
}
let a = new Animal('Cat');
console.log(a.name);
           

這樣編譯就會報錯,因為私有屬性是不可以在外部被通路的。

class Animal {
    protected name;
    public constructor(name) {
        this.name = name;
    }
}

class Cat extends Animal {
    constructor(name) {
        super(name);
        console.log(this.name);
    }
}
           

受保護的屬性是可以再子類中被通路,但是不能在外部通路。

抽象類

所謂抽象類,就是不能執行個體化的類,這種類就是為了子類而存在的,他們的子類可以執行個體化。

抽象類還有抽象方法,抽象方法可以再抽象類中定義,不去做實作,在子類中必須實作抽象方法。關鍵字是abstract

abstract class Animal {
    public name;
    public constructor(name) {
        this.name = name;
    }
    public abstract sayHi();
}

class Cat extends Animal {
    public eat() {
        console.log(`${this.name} is eating.`);
    }
}

let cat = new Cat('Tom');
           

這樣會報錯,因為還有一個抽象方法沒有寫實作。

類與接口

接口的實質是對象的形狀,那麼接口可以規定對象,可以規定類嗎?

答案是啊可以的

interface Alarm {
    alert();
}

class Door {
}

class SecurityDoor extends Door implements Alarm {
    alert() {
        console.log('SecurityDoor alert');
    }
}

class Car implements Alarm {
    alert() {
        console.log('Car alert');
    }
}
           

這裡抽象出來一個接口,叫做警鈴。門有門鈴功能,車有警鈴功能,那麼把這兩個類共有的東西抽象出來,就是類的接口。

接口規定,這個類必須有這個屬性,至于能不能有其他的東西,接口不管。如果類可以抽象出來多個接口,那麼也可以使用多個接口規定同一個類

interface Alarm {
    alert();
}

interface Light {
    lightOn();
    lightOff();
}

class Car implements Alarm, Light {
    alert() {
        console.log('Car alert');
    }
    lightOn() {
        console.log('Car light on');
    }
    lightOff() {
        console.log('Car light off');
    }
}
           

接口還有一種很特殊的繼承性,子接口可以繼承父接口的規則。

interface Alarm {
    alert();
}

interface LightableAlarm extends Alarm {
    lightOn();
    lightOff();
}
           

個人不是很喜歡這種繼承,确實可以再項目擴大之後,寫的更加簡略比如上面的

class Car implements Alarm, Light {
    alert() {
        console.log('Car alert');
    }
    lightOn() {
        console.log('Car light on');
    }
    lightOff() {
        console.log('Car light off');
    }
}
           

此時可以簡寫為

class Car implements Light {
    alert() {
        console.log('Car alert');
    }
    lightOn() {
        console.log('Car light on');
    }
    lightOff() {
        console.log('Car light off');
    }
}
           

但是這時如果Light是多層的嵌套的時候,你就會很疑惑他的規則到底是什麼。想要查清楚需要追溯到最上面一層,就好像一個樹,你得看完他所有節點才能清楚的知道全部,對于ts的檢查來說自然無所謂,但是對于寫代碼的人來說,就很煩,尤其是在沒有完善的文檔的情況下。

接口還可以直接從類裡繼承

class Point {
    x: number;
    y: number;
}

interface Point3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};
           

對這種東西,個人表示也不太喜歡,理由基本同上。