2017-11-25 108 views
1

我想定義不同的數字類型,讓我無法將它們意外,混合起來就像這樣:如何在打字稿中創建不同的數字類型?

let h = 0 as Height; 
let w = 0 as Width; 

// These shall panic 
h === w; 
h + w; 

// These shall work 
(h as number) === (w as number); 
(h as number) + (w as number); 

類型別名不工作,因爲他們僅僅是爲了方便,並且被視爲相同類型:

// This definition works but does not enforce type checking over just 
// using 'number' 
type Height = number; 
type Width = number; 

有關如何解決此問題的任何想法?

編輯:補充規定,即(h + w)將失敗過

+0

你可以像'type Height = number&{__h:never}一樣瘋狂地進行破解| {__h:從不};鍵入Width = number&{__w:never} | {__w:從不}},但是這也會阻止'h + h;' –

回答

0

您可以指定類型,不同類型的號碼的唯一方法是在嘲弄一個接口和一個獨特的領域分配到的接口。

interface IHeight { height: any } 
interface IWidth { width: any } 

declare type Width = number & IWidth; 
declare type Height = number & IHeight; 

let h = 0 as Height; 
let w = 0 as Width; 

現在你不能沒有它再次鑄造數量做h = w直接。

+0

謝謝你的回答謝恩!這是非常有說服力的,嚴格來說,它完全適用於這個問題。但是,雖然構建失敗,但其他運算符(如「h + w」)被允許,這限制了此方法的有用性。我會說這是一個50%的解決方案, 肯定比使用'號碼更好。 – zupa

+0

打字稿中沒有辦法限制該行爲,因爲javascript允許算術運算符使用所有基元類型。你可以做到這一點的唯一方法是使用外部linting程序並設置一個自定義的lint規則。 [TSLint](https://github.com/palantir/tslint)允許自定義規則,您可以在此添加自定義類型到添加運算符規則。 –

0

這可能是矯枉過正,但我​​使用類來防止意外等價,例如與實體ID。我也使用類來封裝單元 - 所以這既能保證類型安全,又能讓您擁有單位轉換的合理歸宿。

class Width { 
    constructor(private value: number) { } 

    get pixels() { 
    return this.value; 
    } 
} 

class Height { 
    constructor(private value: number) { } 

    get pixels() { 
    return this.value; 
    } 
} 

這假定您使用標準單位創建尺寸。你可以添加額外的屬性訪問器來獲取不同單位的高度(如CM,英寸等)。

當您使用WidthHeight它們互不兼容,所以你不能混合起來:

function getArea(width: Width, height: Height) { 
    return width.pixels * height.pixels; 
} 

// number not assignable to `Width` 
getArea(3, 4); 

// `Height` is not assignable to `Width` 
getArea(new Height(2), new Width(4)); 

// `Width` is not assignable to `Height` 
getArea(new Width(2), new Width(4)); 

// Ok 
getArea(new Width(2), new Height(4)); 

在大多數情況下,你會使用這個最終到終端的類型安全(就好像你在飛行中創建一個new Width(5) ......誰是說5是寬度 - 所以你試圖阻止的錯誤仍然會在蠕變中)。所以在大多數情況下,您會從返回WidthHeight的東西中獲得值,並且會阻止傳統的...... obj.Heigl號碼意外地作爲高度傳遞。

const sizes = new SizeProvider(); 

// No 
getArea(sizes.Height, sizes.Width); 

// Ok 
getArea(sizes.Width, sizes.Height); 
+0

謝謝芬頓!我正在尋找替代方法,因爲這也失敗了'a + b',迫使人們使用'a.pixel()+ b.pixel()',但如果'a'和'b'是不同的類型, ,我們又失去了安全類型。 (例如,它們是傳入的對象的屬性。)所以我覺得這種方法與Shane提出的方法具有相同的實用性,但我發現另一種方法更簡單。 – zupa