從兩個角度理解 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