gpt4 book ai didi

typescript - 假运算符重载

转载 作者:行者123 更新时间:2023-12-05 05:32:23 46 4
gpt4 key购买 nike

JS/TS 对StringNumberBoolean 类型进行自动装箱和拆箱,允许混合使用文字和对象在同一个表达式中,没有显式转换,例如:

const a = "3"+ new String("abc");

我正在尝试通过提供自定义类 Longbigintnumber 实现类似的功能:

class Long {
public constructor(private value: bigint | number) { }

public valueOf(): bigint {
return BigInt(this.value);
}
}

const long = new Long(123);
console.log(456n + long);

这工作得很好(并打印 579n),但会导致我的 linter 和 TS 编译器显示最后一个表达式的错误。我可以用这样的评论来压制它们:

// @ts-expect-error
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
console.log(456n + long);

但这对于整个应用来说并不是一个好的解决方案。

有没有办法告诉 Long 将被视为 bigint 或其他任何避免错误的方法?

关于为什么这样做:

我正在开发一种工具来转换 Java to Typescript,并希望支持尽可能多的 Java 语义。 Long 类型包含一个 long 整数,它是 64 位宽,在 TS 中只能使用 bigint 表示。这样做的主要问题是 Java 会自动拆箱 Long 就像 String 一样,我想尽可能地支持这种语义。

对于@caTS:所以这永远不会是普通的 TS 代码,而是始终用作 java.lang.Long,因此不会造成混淆。

最佳答案

您想要的行为,即 TypeScript 允许您使用自定义类 that overrides the Object.prototype.valueOf() method,就好像它是 valueOf() 返回的原始类型一样,不幸的是,这不是该语言的一部分。在 microsoft/TypeScript#2361 上有一个相当长的开放功能请求,但尚未实现,而且看起来不会很快实现。

目前,这意味着只有变通办法。您可以使用的一种解决方法是对编译器撒谎,说 Long 有一个返回原始实例的 construct signature。也就是说,您希望它具有 new (value: bigint | number) => bigint; 类型(或者 new (value: bigint | number) => bigint & Long code> 以便您保留添加到 Long 的任何额外方法或功能。

以下是您可以如何做到这一点:

// rename
class _Long {
public constructor(private value: bigint | number) { }

public valueOf(): bigint {
return BigInt(this.value);
}
}

// assign and assert
const Long = _Long as
new (value: bigint | number) => bigint & _Long;

我在这里重命名了您原来的 Long 构造函数,因为一旦您声明了 class Long { }Long 就得到了自动构造一个构造函数类型,您不能更改该类型。

然后我将重命名的构造函数分配给名为 Long 的所需变量,并且 asserted 它是所需类型,new (value: bigint | number) => bigint & _Long 而不是实际类型,new (value: bigint | number) => _Long

我需要使用类型断言,因为编译器会提示简单的赋值;它知道 Long 的实例类型不是 bigint


好的,现在我们有一个名为 Long 的类构造函数,编译器认为它会生成 bigint 实例。让我们测试一下:

const long = new Long(123);
// const long: bigint
console.log(456n + long); // okay, 579

看起来不错。我可以调用 new Long(123),编译器认为结果是 bigint。它还让我可以毫无怨言地使用像 + 这样的数学运算符,结果就是您所期望的。


所以这和我想象的一样有效。尽管如此,我通常不会故意对编译器撒谎,因为这样的谎言以后可能会以奇怪的方式使您陷入困境。 long 的类型显然不是 bigint:

console.log(typeof long); // "object", not "bigint"

因此任何依赖于 long 的操作实际上是一个 bigint 可能会做一些编译器无法捕获的有趣事情,所以你会看到意想不到的运行时行为:

const bigint1 = BigInt(4);
const bigint2 = BigInt(4);
console.log(bigint1 === bigint2); // true

const long1 = new Long(4);
const long2 = new Long(4);
console.log(long1 === long2); // false!

function copy<T extends {}>(x: T) {
return (typeof x === "object") ? { ...x } : x
}

const bigint3 = copy(bigint1);
console.log(bigint3 + 1n) // 5

const long3 = copy(long1);
console.log(long3 + 1n) // "[object Object]1" 🤪

现在在问题中提到的特定用例中,由于将生成所有 TypeScript 代码,因此您可以保证不会生成任何绊倒这些绊脚石的代码。但即便如此,了解这些事情并在决定是否要继续时将它们考虑在内也很重要。

Playground link to code

关于typescript - 假运算符重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74144649/

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