TypeScript學習筆記之物件型別
原文地址:banggan.github.io/2019/01/21/… 在TypeScript中,利用介面(Interfaces)來定義物件的型別。
在面嚮物件語言中,介面(Interfaces)、它是對行為的抽象,而具體如何行動需要由類(classes)去實現(implements)。 在TypeScript中沒有介面的概念,在編譯成JavaScript的時候,所有的介面會被擦出掉,而TypeScript的核心之一就是型別檢查。 在TypeScript裡,介面的作用就是為這些型別命名和為你的程式碼或第三方程式碼定義契約並讓程式碼看起來更好理解。
TypeScript中的介面
可用於對物件的形狀進行描述,也可用於對類的一部分進行抽象,如:
interface Person { name:string; age:number; } function put(person:Person){ console.log("hello" + person.name+"I'm"+ person.age); } let Tom: Person = { //這裡的物件只要包含必要的屬性且值型別正確就可以 name: 'Tom', age: 25 }; 複製程式碼
如果不給傳進去的物件指定是介面型別的資料,那麼傳入的物件引數可以包含其他屬性,編譯器會檢查必要的屬性是否存在且判斷型別是否正確。 如果是是指定了介面型別的資料,多屬性和少屬性均會出錯
let Tom: Person = {//兩種情況均不允許 name: 'Tom' }; let Tom: Person = { name: 'Tom', age: 25, gender: 'male' }; 複製程式碼
可選屬性
在實際的開發中,接口裡的屬性不全是需要的,就可以使用可選屬性:
帶有可選屬性的介面與普通的介面定義差不多,只是在可選屬性名字定義的後面加一個?符號。
//這裡name和age均是可選屬性,在傳物件的時候name和age可有可無 interface Person { name?: string; age?: number; } function getInfo(p:person){ console.log(p.name); console.log(p.age); } let Tom ={name:'tom'} let Tom ={age:20} getInfo(Tom); 複製程式碼
任意屬性
如果我們希望一個藉口有任意的屬性,可使用 [propName: string]: any來實現:
interface Person { name: string; age?: number; [propName: string]: any; } let Tom: Person = { name: 'Tom', gender: 'male' }; 複製程式碼
一旦定義了任意屬性,則確定和可選屬性必須是他的子屬性。
let tom: Person = { name: 'Tom', age: 25, gender: 'male' }; //error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'. 複製程式碼
這裡的任意屬性是string,而age是number,number不是string的子屬性,所以報錯
只讀屬性
如果我們希望物件的屬性只能在物件建立時候修改其值,在屬性名的前面用readonly來指定只讀屬性:
interface Person { readonly id: number; name: string; age?: number; [propName: string]: any; } let tom: Person = { id: 89757, name: 'Tom', gender: 'male' }; tom.id = 9527; //error TS2540: Cannot assign to 'id' because it is a constant or a read-only property. 複製程式碼
定義只讀陣列
TypeScript具有ReadonlyArray型別,它與Array相似,只是把所有可變方法去掉了,因此可以確保陣列建立後再也不能被修改:
let a: ReadonlyArray<number> =[1,2,3,4]; a[0] =2;//error a.length = 9;//error 複製程式碼
函式型別
為了使用介面表示函式型別,我們需要給介面定義一個呼叫簽名。 它就像是一個只有引數列表和返回值型別的函式定義。引數列表裡的每個引數都需要名字和型別。
interface getStr{ /* 函式傳入兩個number型別的引數,返回一個string*/ (x:number,y:number):string; } let myStr: getStr; myStr = function(grade:number,class:nember){ return `${grade}年級${class}班`; } console.log(myStr(2,3)); //2年級3班 複製程式碼
可索引型別
與使用介面描述函式型別差不多,我們也可以描述那些能夠“通過索引得到”的型別,比如a[10]或ageMap["daniel"]。 可索引型別具有一個 索引簽名,它描述了物件索引的型別,還有相應的索引返回值型別
interface StringArray { [index: number]: string; } let myArray: StringArray; myArray = ["Bob", "Fred"]; let myStr: string = myArray[0];//列印Bob 複製程式碼
定義了StringArray介面,它具有索引簽名。 這個索引簽名表示了當用 number去索引StringArray時會得到string型別的返回值
TypeScript支援兩種索引簽名:字串和數字。 可以同時使用兩種型別的索引,但是數字索引的返回值必須是字串索引返回值型別的子型別。 這是因為當使用 number來索引時,JavaScript會將它轉換成string然後再去索引物件。 也就是說用 100(一個number)去索引等同於使用"100"(一個string)去索引,因此兩者需要保持一致。
類型別
一個類去實現介面,而不是直接把介面拿來用
interface Clock{ //定義一個由屬性和方法的介面 currentTime:Date; setTime(d:Date); } //Time類實現了Clock介面 class Time implements Clock{ currentTime:Date; setTime(d:Date){ this.currentTime = d } constructor(h: number, m: number) { }//類的靜態部分,不會檢查 } 複製程式碼
繼承介面
和類一樣,介面也可以相互繼承。 這讓我們能夠從一個接口裡複製成員到另一個接口裡,可以更靈活地將介面分割到可重用的模組裡。
//介面可以繼承介面並且可以多繼承 interface shape{ color:string; } interface pen extends shape{ width:number; }//建立一個物件並指定泛型 circle.color="red";//這裡可以獲取color屬性 circle.width=2;//有width屬性 複製程式碼
一個介面繼承多個介面,建立多個介面的合成介面
interface Shape { color: string; } interface PenStroke { penWidth: number; } interface pen extends Shape, PenStroke { sideLength: number; } let square = <pen>{}; //建立一個物件並指定泛型 square.color = "blue"; square.sideLength = 10; 複製程式碼
混合型別
所謂的混合型別就是在一個介面中定義多種型別,比如屬性,函式,陣列等:
interface Counter { (start: number): string; interval: number; reset(): void; //沒有返回值的函式 } function getCounter(): Counter { let counter = <Counter>function (start: number) { }; counter.interval = 123; counter.reset = function () { }; return counter; } let c = getCounter(); c(10); c.reset(); c.interval = 5.0; 複製程式碼