1. 程式人生 > 實用技巧 >從兩個角度理解 TypeScript 中的型別是什麼?

從兩個角度理解 TypeScript 中的型別是什麼?

TypeScript中的型別是什麼?本文中描述了兩種有助於理解它們的觀點。

每個角度三個問題

以下三個問題對於理解型別如何工作非常重要,並且需要從兩個角度分別回答。

myvariable具有MyType型別是什麼意思?

letmyvariable: MyType =/*...*/;

SourceType是否可以分配給TargetType?

   let source: SourceType = /*...*/;
   let target: TargetType = source;

TypeUnion是如何從Type1,Type2和Type3派生的?

typeTypeUnion = Type1 | Type2 | Type3;

觀點1:型別是值的集合

從這個角度來看,型別是一組值:

如果myVariable的型別為MyType,則意味著所有可以分配給myVariable的值都必須是MyType集合的元素。

SourceType可分配給TargetType,SourceType是TargetType的子集。結果所有能被SourceType接受的值也被TargetType接受。

型別Type1、Type2和Type3的型別聯合是定義它們集合的集合理論 union。

觀點2:型別相容性關係

從這個角度來看,我們不關心值本身以及在執行程式碼時它們是如何流動的。相反,我們採取了更加靜態的觀點:

原始碼中包含 location,每個 location 都有一個靜態型別。在支援 TypeScript 的編輯器中,如果將游標懸停在 location 上方,則可以看到該 location 的靜態型別。

當源 location 通過分配、函式呼叫等連線到目標 location 時,則源 location 的型別必須與目標 location 的型別相容。 TypeScript 規範通過所謂的型別關係定義型別相容性。

型別關係分配相容性定義什麼時候把源型別S分配給目標型別T:

S和T是相同的型別。
S或T是any型別。

讓我們考慮以下問題:

如果將myVariable的靜態型別分配給MyType,則myVariable的型別為MyType。

如果SourceType是相容分配的,則可以將它們分配給TargetType。

通過型別關係apparent 成員定義型別 union 的工作方式。

TypeScript 型別系統的一個有趣特徵是,同一變數在不同位置可以具有不同的靜態型別:

const arr = [];
// %inferred-type: any[]
arr;

arr.push(123);
// %inferred-type: number[]
arr;

arr.push('abc');
// %inferred-type: (string | number)[]
arr;

東莞vi設計https://www.houdianzi.com/dgvi/ 豌豆資源網站大全https://55wd.com

名義型別系統與結構型別系統

靜態型別系統的職責之一是確定兩種靜態型別是否相容:

實際引數的靜態型別U(例如,通過函式呼叫提供)

對應形式引數的靜態型別T(在函式定義中指定)

這通常意味著檢查U是否為T的子型別。大致有兩種檢查方法:

名義型別系統中,兩個靜態型別如果具有相同的標識(“名稱”)則相等。如果明確聲明瞭它們的子型別關係,則一種型別是另一種型別的子型別。

名義型別的語言為 C ++、Java、C#、Swift 和 Rust。

結構型別系統中,兩個靜態型別具有相同的結構(如果它們具有相同的名稱和相同的型別)則相等。如果U具有T的所有部分(可能還有其他),並且U的每個部分具有T的相應部分的子型別,則型別U是另一種型別T的子型別。

具有結構化型別的語言為 OCaml/ReasonML、Haskell 和 TypeScript。

以下程式碼在名義型別系統中會產生型別錯誤(A 行),但在 TypeScript 的結構型別系統中是合法的,因為類A和類B具有相同的結構:

class A {
  name = 'A';
}
class B {
  name = 'B';
}
const someVariable: A = new B(); // (A)

TypeScript 的 interface 在結構上也可以正常工作 —— 不必為了匹配而實現它們:

interface Point {
  x: number;
  y: number;
}
const point: Point = {x: 1, y: 2}; // OK