Atomic type discrimination (nominal atomic types) in TypeScript

前端 未结 1 872
生来不讨喜
生来不讨喜 2020-12-10 15:01

I\'m just curios, is there a way to discriminate atomic types for greater type safety in TypeScript?

In other words, is there a way to replicate behavior below:

<
1条回答
  •  时光说笑
    2020-12-10 15:56

    Just define it like:

    const marker = Symbol();
    
    export type Kilos = number & { [marker]?: 'kilos' };
    export const Kilos = (value = 0) => value as Kilos;
    
    export type Pounds = number & { [marker]?: 'pounds' };
    export const Pounds = (value = 0) => value as Pounds;
    

    Then Pounds and Kilos are auto casted on numbers and from numbers, but not on each others.

    let kilos = Kilos(0);
    let pounds = Pounds(0);
    let wrong: Pounds = Kilos(20); // Error: Type 'Kilos' is not assignable to type 'Pounds'.
    
    kilos = 10; // OK
    pounds = 20;  // OK
    
    let kilos2 = 20 as Kilos; // OK
    let kilos3: Kilos = 30; // OK
    
    pounds = kilos;  // Error: Type 'Kilos' is not assignable to type 'Pounds'.
    kilos = pounds; // Error: Type 'Pounds' is not assignable to type 'Kilos'.
    
    kilos = Kilos(pounds / 2); // OK
    pounds = Pounds(kilos * 2); // OK
    
    kilos = Pounds(pounds / 2); // Error: Type 'Pounds' is not assignable to type 'Kilos'.
    
    kilos = pounds / 2; // OK
    pounds = kilos * 2; // OK
    

    If you want to prevent auto cast from "enhanced" unit to "plain" number then just remove optional from marker field:

    const marker = Symbol();
    export type Kilos = number & { [marker]: 'kilos' };
    // ------------------------------------^ -?
    export const Kilos = (value = 0) => value as Kilos;
    
    // then:
    const kilos = Kilos(2); // OK
    kilos = 2; // Error
    kilos = kilos * 2; // Error
    

    0 讨论(0)
提交回复
热议问题