基本類型(Basic Types)
為了讓程序可以使用,我們需要用到一些最簡單的數據單元:數字,字符串,結構,布爾值,諸如此類。在TypeScript中,支持許多正如你在JavaScript中期待的相同類型,並且彈窗提示的枚舉類型很方便。
布爾值(Boolean)
最基本的數據類型是簡單的true/value值,JavaScript和TypeScript(包括其他語言)把這個稱作“boolean”值。
var isDone: boolean = false;
數值(Number)
和在JavaScript中一樣,TypeScript中的所有數字都是浮點值。這些浮點值的類型都是“number”。
var height: number = 6;
字符串(String)
在JavaScript中,頁面和服務器之類創建程序的另一個基礎部分是使用文本數據工作。和其它語言一樣,我們使用“string”引用這些文本數據類型。就像JavaScript,TypeScript也使用雙引號或單引號來包裹字符串數據。
var name: string = "bob"; name = 'smith';
數組(Array)
TypeScript和JavaScript一樣,允許使用數組值。數組類型有兩種寫法。第一種,使用數組中的元素的類型后跟中括號“[]”來標志元素類型的數組:
var list:number[] = [1, 2, 3];
第二種方式,使用泛型的數組類型,Array<elemType>:
var list:Array<number> = [1, 2, 3];
枚舉(Enum)
“enum”是TypeScript對JavaScript的標准數據類型集的有用的擴展。像C#語言一樣,一個枚舉是一種更友好地給出數值集合的名字的方式。
enum Color {Red, Green, Blue}; var c: Color = Color.Green;
默認情況下,枚舉類型的成員是從0開始計數的。可以手動地通過設置成員的值來改變默認的計數規則。比如,我們可以從1開始而不是0開始:
enum Color {Red = 1, Green, Blue}; var c: Color = Color.Green;
或者,手動地設置枚舉的所有值(跟C#語法一樣):
enum Color {Red = 1, Green = 2, Blue = 4}; var c: Color = Color.Green;
枚舉方便的一個特征是可以從一個名字的數值找到枚舉中的值所對應的名字。比如,如果有一個值為2,但是不確定它對應到枚舉中的哪一個名字,那么可以通過下面的方式查看對應的名字:
enum Color {Red = 1, Green, Blue}; var colorName: string = Color[2];alert(colorName);
任意類型(Any)
有時候我們可能要描述一些我們可能不知道的變量類型。這些值可能來自動態內容,比如來自用戶或者第三方類庫。在這些情況下,我們要脫離類型檢查和讓這些值通過編譯時檢查,可以使用“any”進行標志:
var notSure: any = 4; notSure = "maybe a string instead"; notSure = false;//最后是一個布爾值
“any”是處理現有的JavaScript的一種強有力的方式,允許慢慢地在編譯期間選擇加入和退出類型檢查。
如果知道一部分類型但也許不是所有類型,這時“any”類型也很方便。比如,有個數組,但是這個數組混合了不同類型的值:
var list:any[] = [1, true, "free"];list[1] = 100;
Void
也許”any”在很多方面與“void”相對,即根本不存在任何類型。通常,這個用於不返回任何值的函數的返回類型。
function warnUser(): void { alert("This is my warning message"); }
接口(Interfaces)
TS的核心原則之一是關注值的類型檢查,有時也叫“動態類型”或“結構化子類型”。在TS中,接口扮演了命名這些類型的角色,它是在你的代碼內部和項目外部定義約定的強大方式。
第一個接口
了解接口如何工作的最簡單的方式是開始一個簡單的例子:
1 function printer(labelObj:{label:string}) { 2 console.log(labelObj.label); 3 } 4 var myObj = { size: 10, label: "size 10 object" }; 5 printer(myObj);
類型檢查器會檢測“printer”的調用,“printer”函數只有一個參數,該參數要求傳入的對象有一個名為“label”的string類型參數。注意,實際上我們例子中傳入的對象有更多的屬性,但是編譯器的檢測機制是這樣的,傳入的對象的屬性最少存在一個和要求的同名,並且類型匹配。
我們再次寫一下這個例子,這次使用接口來描述,該接口有一個string類型的“label”屬性:
1 interface LabelValue{ 2 label:string; 3 } 4 5 function printLabel(labelObj:LabelValue) { 6 document.write(labelObj.label); 7 } 8 var myObj = { size: 10, label: "size 10 object" }; 9 printLabel(myObj);
接口“LabelValue”是一個我們可以用來描述之前例子里的需求的名字。它仍表示了一個具有string類型的“label”屬性。注意,我們我們傳入“printLabel”方法中的對象不必像其他語言一樣顯示實現該接口。這里它只是要緊的模型。如果我們傳入函數的對象滿足列出的需求,那么傳入的對象是被允許的。
值得指出的是,類型檢查器對這些屬性的順序不做要求,只要求存在接口定義的這些屬性,並且類型匹配。
可選屬性
並不是接口的所有屬性都是必須要滿足的。一些屬性可能在一定的條件下存在或者可能根本不存在。當用戶創建像”選項包”時,此時用戶給一個只有兩個屬性要填充的函數傳入一個對象,可選屬性就派上用場了。
下面是此模式的一個例子:
1 function createSquare(config:SquareConfig):{color:string;area:number} { 2 var newSquare = { color: "white", area: 100 }; 3 if (config.color) { 4 newSquare.color = config.color; 5 } 6 if (config.width) { 7 newSquare.area = config.width * config.width; 8 } 9 return newSquare; 10 } 11 12 var mySquare = createSquare({ color: "red" });
具有可選屬性的接口和其他接口寫法相似,只不過它的每一個可選屬性在聲明時,用一個”?”進行標注。
可選屬性的優勢在於你可以描述這些可能是可利用的屬性,然而也會捕獲可能不可用的屬性。
函數類型
接口可以描述廣泛的JavaScript對象可以構建的模型,除了描述具有屬性的對象之外,接口還可以描述函數類型。
為了描述具有接口的方法類型,我們給該接口一個調用簽名。這就像一個只有參數列表和給定返回類型的方法聲明。
1 //函數類型接口的聲明 2 interface SearchFunc { 3 (source:string,substring:string):boolean; 4 } 5 6 var mySerach: SearchFunc; 7 mySerach = function (source: string, substring: string) { 8 var result = source.search(substring); 9 if (result==-1) { 10 return false; 11 } else { 12 return true; 13 } 14 };
一旦定義了函數類型接口,就可以像其他接口一樣使用,這里,我們演示了如何創建函數類型的變量以及給它賦一個相同類型的函數值。
對於函數類型的正確類型檢查,不需要匹配參數的名字,比如上面例子的“source”命名為“src”。
方法參數每次只檢查一次,相互檢查每一個相應的參數的類型。上面的例子,我們的函數表達式返回的值(true和false)暗示了它的返回類型。如果上面返回的是number或string類型的值,類型檢查器會警告我們“返回的類型不匹配在SearchFunc接口中描述的返回類型”。
類類型(Class Types)
實現一個接口
在像C#和Java語言中,接口最通常的用法之一是,顯式地強一個類滿足一個特定的契約,這在TypeScript中也是可以的。
1 interface ClockInterface { 2 currentTime: Date; 3 setTime(d:Date); 4 } 5 class Clock implements ClockInterface { 6 currentTime: Date; 7 constructor(h: number, m: number) { }; 8 setTime(d: Date) { 9 this.currentTime = d; 10 } 11 }
接口描述了類的公共的部分,而不是公共和私有兩部分。這會阻止你使用它們來檢查一個類的實例的私有部分也有特定的類型。
類的靜態/實例端之間的區別
當使用類和接口時,它幫助記憶類有兩種類型:靜態類型和實例類型。你可能會注意到,如果你使用構造簽名創建了一個接口,並且嘗試創建一個實現了該接口的類時,你會得到一個錯誤:
1 /***************錯誤的寫法***************/ 2 interface ClockInterface { 3 new (hour: number, minute: number); 4 } 5 6 class Clock implements ClockInterface { 7 currentTime: Date; 8 constructor(h: number, m: number) { } 9 } 10 /**************錯誤的寫法****************/ 11 /***************正確的寫法***************/ 12 interface ClockStatic { 13 new (hour: number, minute: number); 14 } 15 16 class Clock2{ 17 currentTime: Date; 18 constructor(h: number, m: number) { } 19 } 20 21 var cs: ClockStatic = Clock; 22 var newClock = new cs(7, 30); 23 /**************正確的寫法****************/
這是因為,當一個類實現一個接口時,只會檢測類的實例端,因為constructor位於靜態端,所以會被檢測到。相反,你可能需要直接使用類的“靜態”端。
繼承接口(Extends Interfaces)
像類一樣,接口也可以互相繼承。它處理復制一個接口的成員到另一個接口的任務,在如何分離接口為可重用的組件時給你更多的自由。
1 interface Shape { 2 color: string; 3 } 4 5 interface Square extends Shape { 6 sideLength: number; 7 } 8 9 var square = <Square>{}; 10 square.color = "blue"; 11 square.sideLength = 10;
一個接口可以繼承多個接口,這樣就創建了所有接口的組合。
1 interface Shape { 2 color: string; 3 } 4 5 interface PenStroke { 6 penWidth: number; 7 } 8 9 interface Square extends Shape, PenStroke { 10 sideLength: number; 11 } 12 13 var square = <Square>{}; 14 square.color = "blue"; 15 square.sideLength = 10; 16 square.penWidth = 5.0;
雜交類型(Hybrid Types)
1 interface Counter { 2 (start: number): string; 3 interval: number; 4 reset(): void; 5 } 6 7 var c: Counter; 8 c(10); 9 c.reset(); 10 c.interval = 5.0;
當和第三方JavaScript交互時,你可能需要使用像上面的模式來完全描述該類型的模型。