我一直试图弄清楚如何在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.
有没有办法创建两种类型的数字,但彼此不兼容?
编辑:正如评论部分所述,此行为似乎与haskell的newtype
行为类似。
EDIT2:经过几个小时用棘尖的棍子戳问题后,我设法得到了一个答案,我在下面发布了这个答案。
答案 0 :(得分:1)
TypeScript中与newtype
最接近的是创建一个新的"名义上的" type(TypeScript没有标称类型,但有像branding这样的解决方法)并创建一个值构造函数和一个字段访问器函数,它只在实现中使用类型断言。例如:
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
类型Height
和Weight
(抱歉,不能让自己给新类型一个小写的名称)被编译器视为不同的类型。 height()
函数是Height
值构造函数(采用number
并返回Height
),inches()
函数是其关联的字段访问器(采用Height
并返回number
),weight()
和pounds()
是Weight
的类似函数。所有这些函数都只是运行时的标识函数。因此,JavaScript将它们视为具有一些函数调用开销的纯数字,并且希望通过一个好的编译器进行优化,如果你真的真的担心这个开销,你可以自己做断言:
const h = 12 as any as Height;
const w = 2000 as any as Weight;
现在您可以使用不同的命名类型,因此您不会意外地使用需要Height
的{{1}},反之亦然。但是,就像Weight
一样,编译器不会将它们视为newtype
。是的,您可以number
Height
Weight
的子类型(通过交叉点类型),但这可能是一个错误:像number
这样的算术运算符能够要对+
值进行操作,如果number
和h
都是w
的子类型,那么number
将不会出错。如果h + w
和h
不是 {/ 1}}的子类型,那么w
将是一个错误。并且你无法改变它,因为TypeScript不允许你改变运算符the way it does with functions的类型声明。我希望阻止编译number
和h + h
,因此h + h
和h + w
类型不是Height
。相反,让我们创建我们自己的Weight
函数,它的行为如你所愿:
number
add()
函数接受 两个type Dimension = Height | Weight;
function add<D extends Dimension>(a: D, b: D): D {
return ((a as any) + (b as any)) as any;
}
或两个add()
参数,并返回相同类型的值。实际上,通过上述内容,它仍然可以传递Height
作为Weight
之类的内容,所以如果您真的认真地将其锁定,则可以使用重载:
Height | Weight
看哪:
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;
}
功能,您只需将返回类型声明为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
:
measureScale()
验证预期结果:
Weight
希望有所帮助;祝你好运!
答案 1 :(得分:-1)
所以,在我的头撞墙几个小时之后,我设法得到了这个:
class height extends Number {}
class weight extends Number {}
通过对Number
类进行子类化,Typescript允许您创建不同的数字类型。
然后你可以使用上面指定的变量。
var a: height = 68;
var b: weight = 184;
console.log(a+b); // Should be an error.
我遇到的问题是这也会返回错误:
console.log(a+a); // Should NOT be an error.