【问题标题】:How to type check a binary type alias in Typescript如何在 Typescript 中检查二进制类型别名
【发布时间】:2020-05-27 21:38:48
【问题描述】:

我想根据参数的给定类型来依赖条件,但由于所有可能的参数都是相同的二进制类型(数字),我寻找一种方法来创建某种类型的别名,可以检查为了。

这是最初的想法,这是行不通的,因为 typescript 被编译成 javascript,因此 bonus 将始终是 javascript 类型 number

    type Percentage = number;

    class Foo {
      applyBonus(bonus: Percentage | number) {
        if (typeof bonus === 'Percentage') {
          console.log('Percent');
        } else {
          // it's always number, because at execution time we're in javascript land here
          console.log('number'); 
        } 
      }
    }

    let bar = new Foo();
    bar.applyBonus(5);
    bar.applyBonus(6 as Percentage);

这个问题主要关注打字稿语言的可能性,以及是否可以通过打字稿特性来解决。可以很容易地使用像{value:6,type:'percent'} 这样的对象而不是二进制类型编号。

【问题讨论】:

  • 没有运行时检查就无法做到这一点,但您可能会发现这个库很有趣:github.com/gcanti/money-ts
  • TypeScript 使用structural type system,这意味着numberPercentage 代表完全相同的东西。某些语言使用nominal type system,这将允许您描述的内容,但在 TypeScript 中无法区分两个数字(或任何其他结构上等效的)类型。

标签: typescript design-patterns language-features type-alias


【解决方案1】:

Typescript 不是根据事物的名称来打字,而是根据事物的结构来打字。您可以将数字命名为其他名称,但它仍然是一个数字。 Percentage 这里只是一个别名。

执行此类操作的更好方法是创建一个具有独特形状的界面,您可以在运行时轻松识别。

interface Percentage { percentage: number }

class Foo {
   applyBonus(bonus: Percentage | number) {
      if (typeof bonus === 'object') {
         console.log('Percent', bonus.percentage);
      } else {
         console.log('number', bonus); 
      } 
   }
}

new Foo().applyBonus(123)
new Foo().applyBonus({ percentage: 456 })

Playground


或者(我不推荐这个,但在学术上很有趣),你可以继承 Number 并使用它。

class Percentage extends Number { }

class Foo {
   applyBonus(bonus: Percentage | number) {
      if (bonus instanceof Percentage) {
         console.log('Percent', bonus);
      } else {
         console.log('number', bonus); 
      } 
   }
}

new Foo().applyBonus(123)
new Foo().applyBonus(new Percentage(456))

但实际上,我会质疑您对此的需求。我不确定您要在这里完成什么,但可能有一种更简单的方法。

【讨论】:

  • 你的第二个例子正是我想要的。正如我所提到的,我不是在寻找生产代码解决方案,而不是在我计划的演讲中寻找“TS 中可能发生的事情”之类的东西,这种方法非常适合指出您应该采取的一些事情(风险)考虑到转译器语言。非常感谢!
【解决方案2】:

代码示例

type Percentage = number;

    class Foo {
      applyBonus(bonus: Percentage | number) {
        if (typeof bonus === 'Percentage') {
          console.log('Percent');
        } else {
          // NO, IT IS NOT ALWAYS NUMBER BECAUSE OF THAT
          console.log('number'); 
        } 
      }
    }

    let bar = new Foo();
    bar.applyBonus(5);
    bar.applyBonus(6 as Percentage);

真正的原因

JavaScript

JavaScript 以及任何其他编程语言都带有一组原始值。因为es6六个

  • 号码
  • 字符串
  • 布尔值
  • 未定义
  • 符号

如您所见,Percentage 不是其中之一。

你的execution time we're in javascript land here 语句可能是正确的事实是类型“在 JS 上不存在”......并不完全正确,因为类型确实存在于 JS 中,但你示例中的编译代码看起来像这样

class Foo {
    applyBonus(bonus) {
      if (typeof bonus === 'Percentage') {
        console.log('Percent');
      } else {
        console.log('number'); 
      } 
    }
  }

  let bar = new Foo();
  bar.applyBonus(5);
  bar.applyBonus(6);

如果我们查看bar.applyBonus,您将传递一个 5 n 6 这是两个原始值,因为它们都是数字

如果你不相信我打开浏览器的控制台并粘贴这个 typeof 5

和“百分比”!==“数字”

这就是为什么你总是进入 else 的原因。获得instanceof 百分比的唯一方法是创建对象调用百分比:

class Percentage {
  constructor (value) {
     this.value = value;
  }
}

 class Foo {
      applyBonus(bonus) {
        if (bonus instanceof === Percentage) {
          console.log('Percent');
        } else {
          // NO, IT IS NOT ALWAYS NUMBER BECAUSE OF THAT
          console.log('number'); 
        } 
      }
    }

    let bar = new Foo();
    bar.applyBonus(5);
    bar.applyBonus(new Percentage(6));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 2018-07-20
    • 2019-04-27
    • 2017-06-18
    • 2012-09-29
    • 2017-06-12
    相关资源
    最近更新 更多