DEV Community

ScottPony
ScottPony

Posted on

Solving Potential Issues with Type Aliases Using Type Unions and Literal Types

類型聯合(Type Unions)和字面量類型(Literal Types)能有效解決類型別名(Alias Types)可能帶來的問題。類型聯合允許一個變量可以是多種類型之一,通過結合具體的類型定義,可以幫助區分和處理不同的類型,避免混淆。字面量類型通過將變量限制為具體的字面量值,增強了類型系統的嚴格性。結合使用類型聯合和字面量類型,能提供比單純的類型別名更強的類型安全性,減少代碼中的潛在錯誤。

問題

type Meters = number;
type Miles = number;

const landSpacecraft = (distance: Meters) {
  // ... do fancy math ...
}
Enter fullscreen mode Exit fullscreen mode

以上程式碼定義了兩個Alias Type,但其實這兩個都是源於同樣的Type: number。這會造成甚麼潛在問題?如下:
試想,當長度計算的要求接需要以Meter為單位,但當使用者意外傳進了型態為Miles的變數時,landSpacecraft是可以正常執行且在編譯時不會有任何提示。

const distanceInMiles: Miles = 1242;
landSpacecraft(distanceInMiles); // 傳入錯誤的單位類型,沒有報錯
Enter fullscreen mode Exit fullscreen mode

當整個程式碼中不同單位混用的狀況是存在的,那這種情形就很容易發生,一般基本計算可能不會有太大影響,但如果程式用在高精密度的計算應用下,那單位不對可是會差之毫釐,失之千里!

如何避免

這時,前面提到類型聯合(Type Unions)和字面量類型(Literal Types)就可以很方便地來避免這種狀況。

type Meters = number;
type Miles = number;

type Distance = Meters | Miles;
Enter fullscreen mode Exit fullscreen mode
type Meters = {
  unit: 'meters';
  value: number;
};

type Miles = {
  unit: 'miles';
  value: number;
};

type Distance = Meters | Miles;
Enter fullscreen mode Exit fullscreen mode

首先,可以將兩個別名類別使用'|'宣告為聯合類別"Distance"。為了有效區別兩種單位,使用字面量類型(Literal Types)來對兩個別名類別增加屬性使其成為物件型態並使用這些屬性作為之後判斷是使用哪中單位的區別。

接著,對landSpacecraft方法做改寫

const landSpacecraft = (distance: Distance) => {
  if (distance.unit === 'meters') {
    console.log(`Landing spacecraft with distance: ${distance.value} meters`);
    // 使用 meters 進行計算
  } else if (distance.unit === 'miles') {
    console.log(`Landing spacecraft with distance: ${distance.value / 1609.34} meters`);
    // 使用 miles 進行轉換為Meters的計算
  } else {
    console.error('Unknown distance unit');
  }
}

Enter fullscreen mode Exit fullscreen mode

原方法內此時就可以使用類別保護(type guards)來檢查'unit'屬性,針對不同單位來做相對應的處理。

通過這種方式,我們可以確保在程式中不會混淆不同的單位類型,從而提高程式的安全性與可靠性。

Top comments (0)