gpt4 book ai didi

typescript - 如何在 TypeScript 中创建 2 个不兼容的类数字类型?

转载 作者:搜寻专家 更新时间:2023-10-30 20:36:42 27 4
gpt4 key购买 nike

我一直在尝试找出如何在 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:在用尖头棒戳问题几个小时后,我设法找到了答案,我已在下面发布。

最佳答案

在 TypeScript 中最接近 newtype 的是创建一个新的“名义”类型(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

类型 HeightWeight(抱歉,我不能给新类型起一个小写的名字)被编译器视为不同的类型。 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;

现在您可以使用不同的命名类型,这样您就不会在需要 Weight 的地方意外使用 Height,反之亦然。但是,就像 newtype 一样,编译器不会将它们视为 number。是的,您可以使 HeightWeight 成为 number 的子类型(通过交集类型),但这可能是一个错误:像 这样的算术运算符>+ 能够对 number 值进行操作,如果 hw 都是 number 的子类型>,那么h + w就不会报错了。如果 hw 不是 number 的子类型,则 h + h将是一个错误。而且您无法更改它,因为 TypeScript 不允许您更改运算符的类型声明 the way it does with functions .我更喜欢阻止 h + hh + w 编译,所以 HeightWeight 类型是不是 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 | 的东西。 WeightD,所以如果你真的想锁定它,你可以改用重载:

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:

declare function measureScale(): Weight;

var a = height(68);
var b = measureScale();

并验证预期结果:

console.log(add(a,b)); // err
console.log(add(a,a)); // okay

Playground link to code

关于typescript - 如何在 TypeScript 中创建 2 个不兼容的类数字类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48054767/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com