首頁 > 軟體

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

2022-10-30 14:00:03

前言

在 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區別內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com