扩展字符串的 TypeScript 新 class

TypeScript new class that extends String

我目前正在尝试设置 class "AdvancedString"。这个 class 应该通过像这样的方法扩展 String是JSON。目前看起来像这样

class AdvancedString extends String {
    isJSON():boolean{
        var itIs = true;
        try{
            JSON.parse(this.toString());
        } catch (err) {
            itIs = false;
        }       

        return itIs;
    }
}

export{ AdvancedString}

现在效果还不错。如果我用 "SampleString" 创建一个新实例,我会得到

let sample = new AdvancedString("SampleString");
// ExtendedString {[[PrimitiveValue]]: "SampleString"}

如果我执行 toString,我会得到正确的值

sample.toString()
// "SampleString"

但是当我直接调用它时,我希望它表现得像普通字符串一样

sample === "SampleString"
// should return true and sample.toString() === "SampleString"
// should not be necessary

有没有什么方法可以在 TypeScript 中完成,或者这是不可能的?我想使用一个单独的 class 而不是将我的方法添加到 string

的原型中

不幸的是,这是不可能的。对象仍然是对象,不是 === 原始值(字符串)。

相信我,我已经在这个问题上花了几十个小时,你根本无能为力。

你可以变异 String.prototype.isJSON

String.prototype.isJson = () => 'your logic here'

但这不是一个非常干净的解决方案,除非您确定此代码仅保留在您的应用程序中。

P.S。打字稿与此问题无关。

=== 要求类型相同。 AdvancedString 类型的实例与原始字符串或对象字符串的类型不同,因此 === 始终为假。 new String("") === "" 也是假的,同理;前者是String对象,后者是原始字符串

您的 AdvancedString== 原始字符串,但(看起来)仅当您本机使用 class 时;当我 try that in the TypeScript playground 使用 TypeScript 转译 class 语法时,它失败了。但它本机工作:

class AdvancedString extends String {
  isJSON() {
    var itIs = true;
    try {
      JSON.parse(this.toString());
    } catch (err) {
      itIs = false;
    }

    return itIs;
  }
}

const s = new AdvancedString("foo");
console.log(s === "foo"); // false
console.log(s == "foo");  // true

但是,您可能需要考虑使用 AdvancedString 的缺点,因为您的字符串将是对象,而不是基元:

  • 内存影响。分配这些字符串对象比使用原始字符串对内存的影响更大。¹
  • 任何接收您的字符串之一(例如,您可能正在使用的库)并执行 typeof 检查的代码都不会将它们视为(原始)字符串。因此,例如,接受字符串或选项对象的 API 如果将 AdvancedString 实例传递给它,则可能会被误导。发生这种情况时,TypeScript 可能无法警告您,具体取决于库的注释方式(string|object,例如,不会捕捉到它)。

¹ 出于好奇,我这样做了:

const s = "**y";
const a = Array.from({length: 100000}, () => new String("x" * s));

...在空白页上。我最终在内存中有 100,005 String 个实例(我猜有 5 个来自其他地方)占用 3,200,160 字节。相比之下,这个:

const s = "**y";
const a = Array.from({length: 100000}, () => "x" + s);

...仅将原始字符串的数量从 3,830(281,384 字节)增加到 27,533(1,040,120 字节);显然其中一些(但不是全部)被重复使用。

因此,原语约为 741kB,而对象约为 3MB,是内存的四倍多一点。

这只是一项综合测试,但您明白了。