typescript學習

1.TypeScript 基礎類型

  TypeScriptJavaScript中幾乎有相同的數據類型,不一樣的是TypeScript更嚴格,在定義一個變量時須要聲明數據類型。若是不聲明,都認定爲 Any 類型。編程

   a.布爾值           

  最基本的數據類型就是簡單的true/false數組

 let isDone: boolean = false;

  b. 數字

  TypeScript裏的全部數字都是浮點數。 這些浮點數的類型是 number函數

 let decLiteral: number = 6;
 let hexLiteral: number = 0xf00d;
 let binaryLiteral: number = 0b1010;
 let octalLiteral: number = 0o744;

  c.字符串

  字符串用法較多,經常使用有兩種。ui

 1.定義變量   
 let name:string  = "momo";

 2.字符串模版
 let name1:string = "wang";
 let age:number = 24;
 let sences:string = `hello ,my name is ${name}.i am ${age} years old`

  d.數組

  TypeScript像JavaScript同樣能夠操做數組元素。 有兩種方式能夠定義數組。 第一種,能夠在元素類型後面接上 [],表示由此類型元素組成的一個數組:this

  let list:number[] = [1,2,3]

  第二種方式是使用數組泛型,Array<元素類型>spa

 let list:Array<number> = [1,2,3];

   e.元組

  元組類型容許表示一個已知元素數量類型的數組,各元素的類型沒必要相同。設計

 let x:[string,number];
 x = ['hello', 10];  // ok
 x = [10,'hello'];   // error

  f.枚舉

  enum類型是對JavaScript標準數據類型的一個補充。使用枚舉類型能夠爲一組數值賦予友好的名字。3d

 enum Color {Red,Green ,Blue}
 let c:Color = Color.Green;
 console.log(c); // 0

  默認狀況下,從0開始爲元素編號。 你也能夠手動的指定成員的數值.rest

 enum Color {Red = 1,Green ,Blue}
 let c:Color = Color.Green;
 console.log(c); // 2

  枚舉類型提供的一個便利是你能夠由枚舉的值獲得它的名字code

  例如,咱們知道數值爲2,可是不肯定它映射到Color裏的哪一個名字,咱們能夠查找相應的名字:

 enum Color {Red = 1,Green ,Blue}
 let colorNumber:string = Color[2];
 console.log(colorNumber);  // Green

   g.Any

  有時候,咱們會想要爲那些在編程階段還不清楚類型的變量指定一個類型。

  這些值可能來自於動態的內容,好比來自用戶輸入或第三方代碼庫。

  這種狀況下,咱們不但願類型檢查器對這些值進行檢查而是直接讓它們經過編譯階段的檢查。 那麼咱們可使用 any類型來標記這些變量:

 let notSure:any = 4;
 notSure = 'momo';
 notSure = false;

    h.void

  某種程度上來講,void類型像是與any類型相反,它表示沒有任何類型。 當一個函數沒有返回值時,你一般會見到其返回值類型是 void.

  聲明一個void類型的變量沒有什麼大用,由於你只能爲它賦予undefinednull

 let unusable:void = undefined;

 2.變量聲明

  letconst是JavaScript裏相對較新的變量聲明方式。 

   let在不少方面與var是類似的,可是能夠幫助你們避免在JavaScript裏常見一些問題。 

   const是對let的一個加強,它能阻止對一個變量再次賦值。

   letconstES6中有詳細解釋說明,這裏就很少闡述了。

3.數組

  數組解構

 let input = [1, 2];
 let first = input[0], second = input[1];
 console.log(first);

     這建立了2個命名變量 first 和 second。 至關於使用了索引,但更爲方便

 first = input[0];
 second = input[1];

 

   你能夠在數組裏使用...語法建立剩餘變量:

 let [first, ...rest] = [1, 2, 3, 4];
 console.log(first); // 1
 console.log(rest); //  [ 2, 3, 4 ]

  對象解構

let o = {
    a: "foo",
    b: 12,
    c: "bar"
};
let { a, b } = o;

     這經過 o.a and o.b 建立了 a 和 b 。 注意,若是你不須要 c 你能夠忽略它。

     就像數組解構,你能夠用沒有聲明的賦值:

 ({ a, b } = { a: "baz", b: 101 });

  要當心使用解構。 從前面的例子能夠看出,就算是最簡單的解構表達式也是難以理解的。

  尤爲當存在深層嵌套解構的時候,就算這時沒有堆疊在一塊兒的重命名,默認值和類型註解,也是使人難以理解的。

  解構表達式要儘可能保持小而簡單。 你本身也能夠直接使用解構將會生成的賦值表達式。

4.接口

  TypeScript的核心原則之一是對值所具備的結構進行類型檢查

  它有時被稱作「鴨式辨型法」或「結構性子類型化」。

  在TypeScript裏,接口的做用就是爲這些類型命名和爲你的代碼或第三方代碼定義契約

   接口初探

 function text(lableObj) {
    console.log(lableObj.lable);
 }
 var myObj = { size: 10, lable: "size 10" };
 text(myObj);  //size 10

  類型檢查器會查看text的調用。 text有一個參數,並要求這個對象參數有一個名爲lable類型爲string的屬性。

  須要注意的是,咱們傳入的對象參數實際上會包含不少屬性,可是編譯器只會檢查那些必需的屬性是否存在,而且其類型是否匹配。

   然而,有些時候TypeScript卻並不會這麼寬鬆,咱們下面會稍作講解。

  

  下面咱們重寫上面的例子,此次使用接口來描述:必須包含一個lable屬性且類型爲string: 

interface lableValue{
    lable:string;
}
function text(lableObj:lableValue){
    console.log(lableObj.lable);
}
let myObj = {size:10,lable:"size 10"}
text(myObj);  //size 10

  lableValue接口就比如一個名字,用來描述上面例子裏的要求。

  它表明了有一個 lable屬性且類型爲string的對象。

  須要注意的是,咱們在這裏並不能像在其它語言裏同樣,說傳給text的對象實現了這個接口。

  咱們只會去關注值的外形。 只要傳入的對象知足上面提到的必要條件,那麼它就是被容許的。

  還有一點值得提的是,類型檢查器不會去檢查屬性的順序,只要相應的屬性存在而且類型也是對的就能夠。

   可選屬性

  接口裏的屬性不全都是必需的。 有些是隻在某些條件下存在,或者根本不存在。

  可選屬性在應用「option bags」模式時很經常使用,即給函數傳入的參數對象中只有部分屬性賦值了。

interface SquareConfig{
    color?: string;
    width?: number;
}
function creatSquare(config:SquareConfig):{color:string,area:number}{
    let newSquare = {color:"white",area:0};
    if(config.color){
        newSquare.color = config.color;
    }
    if(config.width){
        newSquare.area = config.width;
    }
    return newSquare;
}
let mySquare = creatSquare({color:"black"})
console.log(mySquare); //{ color: 'black', area: 0 }

  帶有可選屬性的接口與普通的接口定義差很少,只是在可選屬性名字定義的後面加一個?符號。

  可選屬性的好處之一是能夠對可能存在的屬性進行預約義,好處之二是能夠捕獲引用了不存在的屬性時的錯誤。

  值得一提的是,被圈上的部分是函數creatSquare的返回值,若是函數沒有返回值,應該標記爲:void

  

   只讀屬性

  一些對象屬性只能在對象剛剛建立的時候修改其值。 你能夠在屬性名前用 readonly來指定只讀屬性:

interface Point{
    readonly x:number;
    readonly y:number;
}

  若是傳入參數時,傳入了接口中沒有的參數,好比:

interface SquareConfig{
    color?: string;
    width?: number;
}
function creatSquare(config:SquareConfig):{color:string,area:number}{
    let newSquare = {color:"white",area:0};
    if(config.color){
        newSquare.color = config.color;
    }
    if(config.width){
        newSquare.area = config.width;
    }
    return newSquare;
}
let mySquare = creatSquare({colour:"black"})

  這個時候會獲得一個錯誤,// error: 'colour' not expected in type 'SquareConfig'

    解決辦法:

  最佳的方式是可以添加一個字符串索引簽名,前提是你可以肯定這個對象可能具備某些作爲特殊用途使用的額外屬性。 若是 SquareConfig帶有上面定義的類型的colorwidth屬性,而且還會帶有任意數量的其它屬性,那麼咱們能夠這樣定義它:

interface SquareConfig {
    color?: string;
    width?: number;
    [propName: string]: any;
}

  咱們稍後會講到索引簽名,但在這咱們要表示的是SquareConfig能夠有任意數量的屬性,而且只要它們不是colorwidth,那麼就無所謂它們的類型是什麼。

 

  函數類型

  除了描述帶有屬性的普通對象外,接口也能夠描述函數類型。

  爲了使用接口表示函數類型,咱們須要給接口定義一個調用簽名。

  它就像是一個只有參數列表和返回值類型的函數定義。參數列表裏的每一個參數都須要名字和類型。

interface SearchFunc{
    (source:string,subString:string):boolean;
}

  這樣定義後,咱們能夠像使用其它接口同樣使用這個函數類型的接口。

  下例展現瞭如何建立一個函數類型的變量,並將一個同類型的函數賦值給這個變量。

interface SearchFunc{
    (source:string,subString:string):boolean;
}

let mySearch:SearchFunc;
mySearch = function(source:string,subString:string){
    let result = source.search(subString);
    return result > -1;
}

  對於函數類型的類型檢查來講,函數的參數名不須要與接口裏定義的名字相匹配。 好比,咱們使用下面的代碼重寫上面的例子:

interface SeachFunc{
    (source:string,subString:string):boolean;
}
let mySeach:SeachFunc;
mySeach = function(src:string,sub:string):boolean{
    let result  = src.search(sub);
    return result > -1;
}

  函數的參數會逐個進行檢查,要求對應位置上的參數類型是兼容的。

  若是你不想指定類型,TypeScript的類型系統會推斷出參數類型,由於函數直接賦值給了 SearchFunc類型變量。

  函數的返回值類型是經過其返回值推斷出來的(此例是 falsetrue)。

  若是讓這個函數返回數字或字符串,類型檢查器會警告咱們函數的返回值類型與 SearchFunc接口中的定義不匹配。

  

  可索引的類型

  與使用接口描述函數類型差很少,咱們也能夠描述那些可以「經過索引獲得」的類型,好比a[10]ageMap["daniel"]

  可索引類型具備一個 索引簽名,它描述了對象索引的類型,還有相應的索引返回值類型。 

interface StringArray{
    [index:number]:string;
}

let myArray:StringArray;
myArray = ["bob","fred"];
let myStr = myArray[0];
console.log(myStr); //bob

  共有支持兩種索引簽名:字符串和數字

  能夠同時使用兩種類型的索引,可是數字索引的返回值必須是字符串索引返回值類型的子類型。

  這是由於當使用 number來索引時,JavaScript會將它轉換成string而後再去索引對象。

  也就是說用 100(一個number)去索引等同於使用"100"(一個string)去索引,所以二者須要保持一致。

class Animal {
    name: string;
}
class Dog extends Animal {
    breed: string;
}

// 錯誤:使用數值型的字符串索引,有時會獲得徹底不一樣的Animal!
interface NotOkay {
    [x: number]: Animal;
    [x: string]: Dog;
}

  你能夠將索引簽名設置爲只讀,這樣就防止了給索引賦值:

interface ReadonlyStringArray {
    readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // error!

 

總結:

1.interface SeachFunc {};  至關於定義了類型,而且只能按照這個類型傳值;

2.let mySeach:SeachFunc;  至關於具體了內容,進行怎麼樣的操做;

3.let myObj = mySeach("wang","w");  至關於實例化;

 

5.類

  下面看一個使用類的例子: 

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet():string {
        return "Hello, " + this.greeting;
    }
}

let greeter = new Greeter("world");
console.log(greeter.greet()); //Hello, world

  咱們聲明一個 Greeter類。這個類有3個成員:一個叫作 greeting的屬性,一個構造函數和一個 greet方法。

  你會注意到,咱們在引用任何一個類成員的時候都用了 this。 它表示咱們訪問的是類的成員.

  最後一行,咱們使用 new構造了 Greeter類的一個實例。 它會調用以前定義的構造函數,建立一個Greeter類型的新對象,並執行構造函數初始化它。

  繼承  

  在TypeScript裏,咱們可使用經常使用的面向對象模式。

  基於類的程序設計中一種最基本的模式是容許使用繼承來擴展示有的類。

class Animal{
    move(distanceInMeters:number = 0){
        console.log(`Animal moved ${distanceInMeters}`);
    }
}
class Dog extends Animal{
    bark(){
        console.log("woof!woof!");
    }
}
const dog = new Dog();
dog.bark();  //woof!woof!
dog.move(10);//Animal moved 10
dog.bark();//woof!woof!

  這個例子展現了最基本的繼承:類從基類中繼承了屬性方法

  這裏, Dog是一個 派生類,它派生自Animal 基類,經過 extends關鍵字。 派生類一般被稱做 子類,基類一般被稱做 超類

  由於 Dog繼承了 Animal的功能,所以咱們能夠建立一個 Dog的實例,它可以 bark()move()

 

class Animal {
    name: string;
    constructor(theName: string) { this.name = theName; }
    move(distanceInMeters: number = 0) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}
class Snake extends Animal {
    constructor(name: string) { super(name); }
    move(distanceInMeters = 5) {
        console.log("Slithering...");
        super.move(distanceInMeters);
    }
}

class Horse extends Animal{
    constructor(name: string) { super(name); }
    move(distanceInMeters = 45){
        console.log("Galloping...");
        super.move(distanceInMeters);
    }
}

let sam = new Snake("Sammy the Python");
let tom:Animal = new Horse("Tommy the Palomino");

sam.move();
tom.move(34);

  這個例子展現了一些上面沒有提到的特性。

  這一次,咱們使用 extends關鍵字建立了 Animal的兩個子類: Horse和 Snake

  與前一個例子的不一樣點是,子類包含了一個構造函數,它 必須調用 super(),它會執行基類的構造函數。

  並且,在構造函數裏訪問 this的屬性以前,咱們 必定要調用 super()。 這個是TypeScript強制執行的一條重要規則。

  這個例子演示瞭如何在子類裏能夠重寫父類的方法。 

  Snake類和 Horse類都建立了 move方法,它們重寫了從 Animal繼承來的 move方法,使得 move方法根據不一樣的類而具備不一樣的功能。

  注意,即便 tom被聲明爲 Animal類型,但由於它的值是 Horse,調用 tom.move(34)時,它會調用Horse裏重寫的方法

相關文章
相關標籤/搜索