Skip to content

Type 與 Interface 的差異

最近在學習TypeScript時,覺得Type跟Interface這兩種定義型別的方式,有種若即若離的關係, 定義型別何時要用type、何時要用Interface呢?自己也無法解釋的很清楚,於是想把在網路上找到的知識, 以及自己的實作做些統整,加深自己的記憶點。

Type

定義型別的一種方法,可採用顯式的定義,也可使用隱式的類型推斷,常用來定義較為簡易的型別類型(較為推薦), 對定義之型別,有較多的操作空間,TypeScript提供了許多工具類型的type供我們使用。可以表示原始類型、聯合類型、元組類型和物件類型。

typescript
//簡易地定義屬性
type Apple = string
//以物件類型定義屬性
type Aaron ={
  year:number;
  kind:string;
  IQ?:number; =>?代表選填
  ():string => 可以被執行
  [key:string]:any =>可以接受任何 index
  new (aaron:string):string => 可以被實例化
  readonly weight:number =>只讀屬性
}

function test(s:aaron){
  console.log( s.IQ,s.year, s())
  return new s('aaron')
}


//工具類型操作 getType
 type GetType<T,K extends keyof T> = {[S in K]:T[S]}
 type c = GetType<aaron, 'year'>
 //type c = {
 //   year: number;
 // }

//工具類型操作 exclude
//利用簡單型別的分配律,去除限制型別,可以把 extends視為限制的關鍵,T 必須符合 K 的條件。
type ExcludeType<T,K extends T> =  T extends K ?  never : T
type a = ExcludeType<'year' | 'age' |'now', 'year'> // age,now

//去除readOnly屬性 -號可以去除modified修飾詞,預設是+readonly,不用+是因為ts編譯時幫我們加上去了。
type Book ={
  readonly buyYear:number;
  readonly kind:string;
  readonly cost:number;
}

type ReadonlyRemove<T> = {-readonly[S in keyof T ]:T[S]}
type x = ReadonlyRemove<Book>

Interface

用來形容或描述物件的結構或屬性的型別,也因為Js有許多物件結構的描述,較能用來描述這些預設的js行為~

typescript

interface myInterFace{
  [propname:string]:any,
  name:string,
  age?:number,
  say():string,
}
interface myInterFace{
  gender:string;
}

const obj:myInterFace = {
  name:'123',
  age:12,
  gender:'12312313123'
}
//定義class時 可以使用 interface規範 所需的屬性
class Myclass implements(實現) myInterFace{

}
// 繼承(擴充)
interface Myclass extends myInterFace{

}

//當然也可以這樣使用
interface cake<T,K>{
  cost:T,
  size:K
}

const a:cake<number,string> ={
  cost:18,
  size:"big"
}

補充 [key:string|number|symbol] 若建立key必須符合以下型別,不然會ERROR。

Type vs Interface

與interface的差異在於無法重複覆值,沒有overload特性及merging特性,並且不能繼承實作物件與其屬性。 而且語意上也有些需差異,需要多方評估後挑適合的使用。

typescript
type Aaron = {year:number,height:number} <-顯式定義
type Aaron = {kind:string} <- Duplicate identifier 'Aaron' 無法合併

interface Hellen {year:number,height:number}
interface Hellen {kind:string} <- Hellen屬性中有year,height,kind => merging 合併了

interface cake{
  cost:string,
  size:number,
  match(s:string):void; //overload
  match(s:number):number; //overload
}

 function testOne (a:cake):number{
//  return a.match('s') // string
 return a.match(18) //number
}


//例如 哪一個更符合座標物件的型別描述呢?
type Point = [number, number];

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

簡單下個結論,就是使用前先思考要定義的是原始的型別,亦或是物件型別,若是物件型別是否需要操作其中的屬性, 還是單純的表示構造屬性,若需要操作就可以考慮type,反之則可以使用interface做為表示~

若有不同的看法,歡迎在下方留言~

TypeScript官網描述TypeScript DeepDive

Released under the MIT License.