TypeScript новый класс, расширяющий String - PullRequest
0 голосов
/ 17 октября 2018

В настоящее время я пытаюсь настроить класс "AdvancedString".Этот класс должен расширять String такими методами, как, например, isJSON.В настоящее время это выглядит так:

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 или это невозможно?Я хотел бы использовать отдельный класс и не добавлять свой метод в прототип строки

Ответы [ 2 ]

0 голосов
/ 17 октября 2018

=== требует, чтобы типы были одинаковыми.Экземпляры вашего типа AdvancedString не имеют того же типа, что и строки примитива или объекта, и поэтому === всегда будет ложным.new String("") === "" также ложно по той же причине;первый является объектом String, последний является примитивной строкой.

Ваш AdvancedString является == примитивной строкой, но только (кажется), если вы используете class изначально;когда я пытаюсь это сделать на игровой площадке TypeScript с 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), занимающих 3200 160 байт.Напротив, это:

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

... только увеличило количество примитивных строк с 3 830 (281 384 байт) до 27 533 (1 040 120 байт);очевидно, некоторые (но не все) из них были повторно использованы.

Так что это ~ 741 КБ для примитивов против ~ 3 МБ для объектов, чуть более чем в четыре раза больше памяти.

Это всего лишь один синтетический тест, но вы поняли.

0 голосов
/ 17 октября 2018

К сожалению, это невозможно.Объект по-прежнему является объектом и не является === для примитивного значения (строки).

Поверьте мне, я потратил десятки часов на эту проблему, вы просто ничего не можете сделать.

Вы можете мутировать String.prototype.isJSON

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

Но это не очень чистое решение, если только вы не уверены, что этот код остается только внутри вашего приложения.

PS Typescript не имеет ничего общего с этой проблемой.

...