使用函数创建自己的Typescript类型

11 浏览
0 Comments

使用函数创建自己的Typescript类型

我正在尝试创建自己的类型,以便可以使用“点语法”调用函数。

例如:

let myOwnType: myByteType = 123211345;
myOwnType.toHumanReadable(2);

我想要实现与数字、数组等相同的行为。

我不想使用调用签名或构造函数签名来创建我的类型。

因此,在查看Typescript库后,我发现了这个数字接口:

interface Number {
    /**
     * 返回对象的字符串表示形式。
     * @param radix 指定将数字值转换为字符串的基数。此值仅用于数字。
     */
    toString(radix?: number): string;
    /**
     * 返回表示以定点表示法显示的数字的字符串。
     * @param fractionDigits 小数点后的位数。必须在0-20的范围内,包括0和20。
     */
    toFixed(fractionDigits?: number): string;
    /**
     * 返回以指数表示法显示的数字的字符串。
     * @param fractionDigits 小数点后的位数。必须在0-20的范围内,包括0和20。
     */
    toExponential(fractionDigits?: number): string;
    /**
     * 返回一个字符串,该字符串包含以指数或定点表示法表示的数字,并带有指定数量的位数。
     * @param precision 有效数字位数。必须在1-21的范围内,包括1和21。
     */
    toPrecision(precision?: number): string;
    /** 返回指定对象的原始值。 */
    valueOf(): number;
}

问题是我找不到函数体被定义的地方和方式。我在想可能有一个实现接口的类或类似的东西。

我试着尝试了这样的方法:

interface Bytes {
  toHumanReadable(decimals: number): bytesToHumanReadable;
  bytesAs(unit: string): string;
}
function bytesToHumanReadable (decimals: number) {
  // 将字节转换为GB、TB等...
}

我如何创建自己的类型并像普通类型一样使用它们?

我知道接口也不起作用,但这是我第一个猜测。

0
0 Comments

问题的出现原因是想要给数字类型添加新的功能,但是需要扩展基本的NumberConstructor接口并自己实现这个功能。解决方法是通过扩展Number原型来实现功能,并使用扩展了myByteType接口的变量来调用该功能。

具体做法是先定义一个接口myByteType,该接口扩展了NumberConstructor接口,并添加了一个toHumanReadable方法。然后通过扩展Number原型来实现toHumanReadable方法。最后,可以使用扩展了myByteType接口的变量来调用toHumanReadable方法。

需要注意的是,通过赋值在内置原型上创建属性不是最佳实践,应该确保属性是不可枚举的。此外,以上代码在给变量赋值时会出现类型错误,可以参考提供的链接进一步了解解决方法。

以下是完整的代码示例:

interface myByteType extends NumberConstructor {
  toHumanReadable: (decimals: number) => string;
}
Number.prototype.toHumanReadable = function (decimals: number) {
  // convert bytes to GB, TB etc..
};
const secondsSinceOpened: myByteType = 1334244200;
secondsSinceOpened.toHumanReadable(2);

注意:以上代码仅为示例,具体的toHumanReadable方法的实现需要根据实际需求进行编写。

0
0 Comments

问题的原因是无法找到函数体是在哪里和如何定义的。函数体是由JavaScript引擎作为标准库的一部分定义的。你可以在Number.prototype上找到它们。工作原理如下:当你尝试访问一个原始值的属性(例如,someNumber.toString()),JavaScript引擎会在该原始值的对象类型的原型上查找该属性(number => Number,string => String,等等)。如果你进行调用,它会调用该方法,传递原始值(在严格模式下)或原始值的对象包装器(在宽松模式下)。

你不能定义自己的原始类型,这只能在JavaScript规范级别上完成。你可以创建一个Byte类并创建它的实例,但它们将是对象,而不是原始值。

class Byte {
    constructor(public value: number) {
    }
    yourMethodHere() {
        // ...
    }
}

你也可以向Number.prototype添加方法,尽管最好不要在与他人共享的任何库代码中这样做(在你自己的应用程序或页面中使用它基本上是可以的,只需确保使用不太可能被标准库的未来特性使用的名称)。

例如,这里将一个toHex方法添加到数字中:

// 添加到类型中
interface Number {
    toHex(): string;
}
// 添加实现
Object.defineProperty(Number.prototype, "toHex", {
    value() {
        return this.toString(16);
    },
    enumerable: false, // 这是默认值,但只是为了强调...
    writable: true,
    configurable: true
});

在线示例

很好的解释。我真的不想向数字原型添加方法,因为可能会出现你已经提到的问题。我将学习更多关于JavaScript引擎本身的知识,可能会使用接口和对象来代替。

0
0 Comments

在上述代码中,问题的出现是因为无法直接在现有的类型上添加自定义函数。解决方法是使用接口来创建自己的类型,并通过添加扩展属性来实现自定义函数。通过使用interface关键字创建一个新的接口myByteType,并将其扩展为Number类型。在接口中定义了一个可选的toHumanReadable函数,用于将数字转换为可读的字符串。

然后,通过使用Object.defineProperty方法将toHumanReadable函数添加到Number.prototype对象上,以实现该函数的实际实现。在这个例子中,toHumanReadable函数将数字转换为十六进制字符串。

最后,通过声明一个变量a并将其类型设置为myByteType,我们可以将数字赋值给a并调用a.toHumanReadable()来使用自定义函数。

通过使用interface和扩展属性的方法,我们可以在TypeScript中创建自己的类型并添加自定义函数,从而解决了无法直接在现有类型上添加函数的问题。这种方法允许我们扩展现有类型的功能,使其更适应我们的需求。

0