TypeScript中type和interface的區別及註意事項

前言

在 TS 中,typeinterface相似,都可以給類型命名並通過該名字來引用表示的類型。不過它們之間是存在一些差別的,我們在使用時也需要註意一些特殊場景。

概念

type

type關鍵字是聲明類型別名的關鍵字。它的語法如下:

type AliasName = Type;
  • type:聲明類型別名的關鍵字
  • AliasName:類型別名的名稱
  • Type:類型別名關聯的具體類型

interface

通過關鍵字 interface可以定義一個接口類型。它能合並眾多類型聲明至一個類型聲明。

接口聲明隻存在於編譯階段,在編譯後生成的 JS 代碼中不包含任何接口代碼。

語法如下:

interface InterfaceName {
  TypeMember;
  TypeMember;
  ...
}
  • interface:定義接口的關鍵字
  • InterfaceName:接口名,首字母需要大寫
  • TypeMember:接口的類型成員

異同點

不同點

  • type 在聲明類型別名之後實際上是一個賦值操作,它需要將別名與類型關聯起來。也就是說類型別名不會創建出一種新的類型,它隻是給已有類型命名並直接進行引用。interface是定義瞭一個接口類型。
  • type 能夠表示非對象類型, 而 interface 則隻能表示對象類型。
  • interface可以繼承其他的接口、類等對象類型, type 不支持繼承。

好多文章裡都說 type 也支持繼承,但是我認為這種說法不嚴謹。對於類型別名來說,它可以借助交叉類型來實現繼承的效果。而且這種方法也隻適用於表示對象類型的類型別名,對於非對象類型是無法使用的。

type Shape = { name: string }

type Circle = Shape & { radius: number }

function foo(circle: Circle) {
  const name = circle.name
  const radius = circle.radius
}

interface接口名總是會直接顯示在編譯器的診斷信息和代碼編輯器的智能提示中,而 type 的名字隻在特定情況下才會顯示出來——隻有當類型別名表示數組類型、元組類型以及類或者接口的泛型實例類型時才展示。

type NumericType = number | bigint;

interface Circle {
  radius: number;
}

function f(value: NumericType, circle: Circle) {
  const bar: boolean = value;
  //    ~~~
  // 	  Type 'number | bigint' is not assignable to type 'boolean'
  // 		這裡沒有顯示類型別名
  
  const baz: boolean = circle;
  // 	  ~~~
  // 		Type 'Circle' is not assignable to type 'boolean'
}
  • interface具有聲明合並的行為,而 type不會,這也意味著我們可以通過聲明合並的方式給 interface定義的類型進行屬性擴展。
  • type可以通過 typeof來獲取實例的類型從而進行賦值操作

相同點

都可以用來定義 對象 或者 函數 的結構,而嚴謹的來說,type 是引用,而 interface是定義。

補充:Ts中type和interface定義類型擴展類型的方法

1、在Ts中,我們可以通過type和interface的方式去定義類型,一般情況下通過interface接口的方法定義的類型都可以通過type去定義。註意type要添加等號。Interface定義類型不需要添加等號。

下面代碼是用type聲明一個string類型的例子

type user=string
//接收一個字符串類型的數據,返回一個user類型(字符串類型)的數據
function Input(str:string):user{
    return str.slice(0,2)
}
//把返回結果賦值給userInput
let userInput=Input('hello')
//重新給其賦值一個字符串類型的值,沒有報錯,說明用type聲明的字符串類型生效
userInput='new'

下面代碼是用interface聲明一個對象類型的例子

interface Point{
    x:number,
    y:number
}
//接收一個Point的對象類型數據
function printCoord(pt:Point){
 
}
//給函數傳一個對象類型的數據,沒有報錯,說明用interface聲明的類型生效
printCoord({
    x:100,
    y:100
})

2、 Interface擴展接口:可以在interface後面添加關鍵字extends去擴展接口。類型別名type需要使用&符號去擴展接口

下面代碼是用extends擴展接口的例子

//擴展接口
interface Animal{
    name:string
}
interface Bear extends Animal{
    honey:boolean
}
//聲明一個類型為Bear類型的對象,要求既要有name,也要有honey。說明用extends擴展接口成功
const bear:Bear={
    name:'winie',
    honey:true
}
console.log(bear.name);
console.log(bear.honey);

 下面代碼是用type擴展接口的例子

//擴展類型
type Animal={
    name:string
}
//給Animal擴展接口
type Bear=Animal&{
    honey:boolean
}
const bear:Bear={
    name:'winie',
    honey:true
}

3、向現有類型添加新字段,interface可以通過定義同名的方式去擴展字段,類型別名type是不能通過同名的方式去進行擴展的。

下面代碼是interface通過定義同名的方式向現有類型添加新字段

//向現有的類型添加新字段
interface MyWindow{
    title:string
}
interface MyWindow{
    count:number
}
const w:MyWindow={
    title:'wz',
    count:666
}

 下面代碼會報錯,因為類型別名type是不能通過同名的方式去進行擴展的。

//類型創建後不能更改
type MyWindow={
    title:string
}
type MyWindow={
 
}

總結

對於 type來說,更多的是對類型的一種復用,比如在項目中需要用到一些比較復雜的或者書寫起來很長的類型。我們可以使用 type來直接引用該類型:

type FType = boolean | string | number;

而對於 interface來說,它是正兒八經的用來定義接口類型(約束數類型和屬性)的,且接口類型是支持繼承和聲明合並的。

所以在對於對象結構的類型定義上,建議盡可能的使用 interface,而在合適的場景使用 type

到此這篇關於TypeScript中type和interface區別及註意事項的文章就介紹到這瞭,更多相關TS type和interface區別內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: