名稱和結構型別
靜態型別檢查器在將型別與其他型別進行比較時 (例如,檢查一個型別是否為另一個型別的子型別時),可以使用型別的名稱 (名稱型別) 或結構 (結構型別)。
名稱型別
C++、Java 和 Swift 等語言主要採用名稱型別系統。
// Pseudo code: nominal system
class Foo { method(input: string) { /* ... */ } }
class Bar { method(input: string) { /* ... */ } }
let foo: Foo = new Bar(); // Error!
在此偽程式碼範例中,儘管兩個類別具有相同名稱和型別的方法,但名稱型別系統仍會產生錯誤。這是因為類別的名稱 (和宣告位置) 不同。
結構型別
Go 和 Elm 等語言主要採用結構型別系統。
// Pseudo code: structural system
class Foo { method(input: string) { /* ... */ } }
class Bar { method(input: string) { /* ... */ } }
let foo: Foo = new Bar(); // Works!
在此偽程式碼範例中,結構型別系統允許將 Bar 用作 Foo,因為兩個類別都具有相同名稱和型別的方法和欄位。
但是,如果類別的形狀不同,結構系統就會產生錯誤
// Pseudo code
class Foo { method(input: string) { /* ... */ } }
class Bar { method(input: number) { /* ... */ } }
let foo: Foo = new Bar(); // Error!
我們已經展示了類別的名稱和結構類型,但也有其他複雜類型,例如物件和函式,它們也可以是名稱或結構比較。此外,類型系統可能同時具有結構和名稱系統的方面。
在 Flow 中
Flow 對物件和函式使用結構類型,但對類別使用名稱類型。
函式是結構類型
當將函式類型與函式進行比較時,它必須具有相同的結構才能被視為有效。
1type FuncType = (input: string) => void;2function func(input: string) { /* ... */ }3let test: FuncType = func; // Works!物件是結構類型
當將物件類型與物件進行比較時,它必須具有相同的結構才能被視為有效。
1type ObjType = {property: string};2let obj = {property: "value"};3let test: ObjType = obj; // Works類別是名稱類型
當您有兩個具有相同結構的類別時,它們仍然不被視為等效,因為 Flow 對類別使用名稱類型。
1class Foo { method(input: string) { /* ... */ } }2class Bar { method(input: string) { /* ... */ } }3let test: Foo = new Bar(); // Error! 3:17-3:25: Cannot assign `new Bar()` to `test` because `Bar` [1] is incompatible with `Foo` [2]. [incompatible-type]
如果您想結構化地使用類別,可以使用介面來執行此操作。
1interface Interface {2 method(value: string): void;3};4
5class Foo { method(input: string) { /* ... */ } }6class Bar { method(input: string) { /* ... */ } }7
8let test1: Interface = new Foo(); // Works9let test2: Interface = new Bar(); // Works不透明類型
您可以使用不透明類型將先前結構化類型的別名轉換為名稱類型(在定義它的檔案外)。
1// A.js2export type MyTypeAlias = string;3export opaque type MyOpaqueType = string;4
5const x: MyTypeAlias = "hi"; // Works6const y: MyOpaqueType = "hi"; // Works在不同的檔案中
// B.js
import type {MyTypeAlias, MyOpaqueType} from "A.js";
const x: MyTypeAlias = "hi"; // Works
const y: MyOpaqueType = "hi"; // Error! `MyOpaqueType` is not interchangable with `string`
// ^^^^ Cannot assign "hi" to y because string is incompatible with MyOpaqueType
Flow 列舉
Flow 列舉不允許具有相同值但屬於不同列舉的列舉成員可以互換使用。
1enum A {2 X = "x",3}4enum B {5 X = "x",6}7
8const a: A = B.X; // Error! 8:14-8:16: Cannot assign `B.X` to `a` because `B` [1] is incompatible with `A` [2]. [incompatible-type]