Typescript: возможно ли объявить класс с помощью функции - PullRequest
1 голос
/ 27 апреля 2020

Читая этот учебник, я вижу, что один из способов объявить класс в Typescript - это использовать синтаксис class следующим образом.

class Person { 
   constructor(name: string) {
      this.name = name
   }
}

И после компиляции он сгенерирует следующий код Javascript .

//Generated by typescript 1.8.10
var Person = (function () {
   function Person(name) {
      this.name = name
   }
   return Person;
}());

Мой вопрос: возможно ли объявить в Typescript класс с использованием сгенерированного синтаксиса Javascript, например, так ...

function Person(name: string) {
  this.name = name
}

Ответы [ 2 ]

2 голосов
/ 28 апреля 2020

Это вроде возможно, но не рекомендуется, согласно microsoft / TypeScript # 2310 . Согласно команде TS, если вы используете TypeScript, вы должны использовать class напрямую. Он будет скомпилирован как есть, если вы нацелены на ES2015 или выше, или он скомпилируется до функции, которую вы упомянули, если вы нацелены на ES5.

Если вы хотите проигнорировать рекомендацию, вы должны сделать некоторые аннотации типов и утверждения, чтобы получить желаемое поведение, и в результате в скомпилированном выводе останется небольшой, но неиспользуемый код времени выполнения. И это не будет особенно безопасно для типов (если вы допустите ошибку при наборе текста, компилятор не будет жаловаться).

Сначала вы должны вручную определить интерфейс вашего экземпляра класса, так как компилятор не может сделайте для вас вывод:

interface Person {
    name: string;
}

Затем вы должны задать для своей функции this параметр , чтобы компилятор понимал, что внутри реализации вашей функции значение this следует рассматривать как экземпляр вашего класса. Вам также следует переименовать функцию из Person во что-то другое (например, _Person), потому что вы не сможете изменить ее тип на что-то new -можное после факта:

function _Person(this: Person, name: string) {
    this.name = name;
}

Наконец, вы можете определить Person как const, значение которого совпадает с вашей переименованной функцией во время выполнения, но во время компиляции вы даете ей сигнатуру конструктора:

const Person = _Person as any as new (name: string) => Person;

Теперь он настроен так, что Person является функцией во время выполнения (не class, даже если вы нацелены на ES2015 +), но чтобы компилятор воспринимал ее как конструктор:

const p = new Person("Alice");
console.log(p.name); // Alice

Итак, ура? Бороться с таким компилятором и «побеждать», вероятно, не стоит в любых производственных условиях. Но интересно посмотреть, как это сделать, я думаю.

Хорошо, надеюсь, это поможет; удачи!

Детская площадка ссылка на код

1 голос
/ 28 апреля 2020

В качестве улучшения уже существующего ответа вы также можете сделать это следующим образом:

interface Person {
    name: string;
}

interface PersonConstructor {
    new(name: string): Person;
}

const Person: PersonConstructor = function (this: Person, name: string) {
    this.name = name;
} as any;

const p = new Person("Alice");
console.log(p.name); // Alice

Таким образом, вы, по крайней мере, сохраните некоторую безопасность типов, если вы все еще заботитесь об этом материале.


Этот способ также позволяет вам определять методы stati c для Person, сначала добавляя их к PersonConstructor. Таким образом, вы можете сделать:

interface PersonConstructor {
    new(name: string): Person;
    foo(bar: string): void;
}

И позже сделать:

Person.foo = (bar: string) => {
    console.log(`foo ${bar}`);
}

И вызвать его с помощью Person.foo("something");

Playground Link

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...