跳至主要內容

名稱和結構型別

靜態型別檢查器在將型別與其他型別進行比較時 (例如,檢查一個型別是否為另一個型別的子型別時),可以使用型別的名稱 (名稱型別) 或結構 (結構型別)。

名稱型別

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]