我一直试图弄清楚如何在TS中创建2个互不兼容的数字/整数类型.
例如,在下面的代码中,高度和重量都是数字,但将它们加在一起或等效处理它们的概念是没有意义的,应该是一个错误.
type height = number; // inches
type weight = number; // pounds
var a: height = 68;
var b: weight = operateScale(); // Call to external, non-TS function, which returns a weight.
console.log(a+b); // Should be an error.
Run Code Online (Sandbox Code Playgroud)
有没有办法创建2个类型,这两个类型都是数字,但彼此不兼容?
编辑:正如评论部分所述,这种行为似乎与haskell的newtype行为类似.
编辑2:经过几个小时用尖尖的棍子戳问题,我设法得到了答案,我在下面发布了.
newtype与 TypeScript 中的a 最接近的是创建一个新的“名义”类型(TypeScript 没有名义类型,但有诸如品牌之类的解决方法)并创建一个值构造函数和一个字段访问器函数,该函数仅在实现中使用类型断言。例如:
interface Height {
__brand: "height"
}
function height(inches: number): Height {
return inches as any;
}
function inches(height: Height): number {
return height as any;
}
interface Weight {
__brand: "weight"
}
function weight(pounds: number): Weight {
return pounds as any;
}
function pounds(weight: Weight): number {
return weight as any;
}
const h = height(12); // one foot
const w = weight(2000); // one ton
Run Code Online (Sandbox Code Playgroud)
类型Height和Weight(抱歉,我无法为新类型指定小写名称)被编译器视为不同的类型。该height()函数是一个Height值构造函数(接受 anumber并返回 a Height),该inches()函数是其关联的字段访问器(接受 aHeight并返回 a number),weight()并且pounds()是 的类似函数Weight。所有这些函数在运行时都只是身份函数。因此,JavaScript 将它们视为纯数字,并带有一些函数调用开销,希望能被好的编译器优化掉,如果您真的担心这种开销,您可以自己进行断言:
const h = 12 as any as Height;
const w = 2000 as any as Weight;
Run Code Online (Sandbox Code Playgroud)
现在,您可以使用不同的命名类型,因此您不会意外地Height在Weight需要a 的地方使用 a ,反之亦然。但是,就像 a 一样newtype,编译器不会将它们视为number. 是的,您可以创建Height和 的Weight子类型number(通过交集类型),但这可能是一个错误:算术运算符 like+能够对number值进行操作,如果两者都是h和w的子类型number,则h + w不会出错。而如果h和w是不是亚型number,那么h + h将是一个错误。你不能改变它,因为 TypeScript 不允许你改变运算符的类型声明将其与功能的方式做。我更喜欢同时阻止h + handh + w编译,所以HeightandWeight类型不是numbers。相反,让我们创建自己的add()函数来按照您的意愿行事:
type Dimension = Height | Weight;
function add<D extends Dimension>(a: D, b: D): D {
return ((a as any) + (b as any)) as any;
}
Run Code Online (Sandbox Code Playgroud)
所述add()函数接受或者2个Height或两个Weight参数,并返回相同的类型的值。实际上,通过上面的内容,仍然可以传入Height | Weightas 之类的内容D,因此如果您真的很想将其锁定,则可以改用重载:
function add(a: Height, b: Height): Height;
function add(a: Weight, b: Weight): Weight;
function add(a: any, b: any): any {
return a+b;
}
Run Code Online (Sandbox Code Playgroud)
而且,看哪:
const twoH = add(h, h); // twoH is a Height
const twoW = add(w, w); // twoW is a Weight
const blah = add(h, w); // error, Height and Weight don't mix
Run Code Online (Sandbox Code Playgroud)
所以我们差不多完成了。对于您的外部measureScale()函数,您只需将返回类型声明为 a Weight:
declare function measureScale(): Weight;
var a = height(68);
var b = measureScale();
Run Code Online (Sandbox Code Playgroud)
并验证预期结果:
console.log(add(a,b)); // err
console.log(add(a,a)); // okay
Run Code Online (Sandbox Code Playgroud)
希望有所帮助;祝你好运!
所以,在我把头撞在墙上几个小时之后,我设法想出了这个:
class height extends Number {}
class weight extends Number {}
Run Code Online (Sandbox Code Playgroud)
通过对类进行子类化Number,Typescript 允许您创建不同的数字类型。
然后您可以使用上面指定的变量。
var a: height = 68;
var b: weight = 184;
console.log(a+b); // Should be an error.
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是这也会返回一个错误:
console.log(a+a); // Should NOT be an error.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
289 次 |
| 最近记录: |