TypeScript: как инициализировать производный класс от объекта? - PullRequest
0 голосов
/ 23 октября 2019

У меня есть следующий код:

class MyClass {
    name: string = "myname";
    constructor(public action: string) { }
}

let obj1: MyClass = { action: "act1" };

Не компилируется. Ошибка в последней строке:

Property 'name' is missing in type '{ action: string; }' but required in type 'MyClass'.

Я ожидал, что, поскольку свойство 'name' имеет значение по умолчанию, я не ожидал бы указать его для obj1. Но это не так. Кроме того, кажется, что последняя строка даже не вызывает ctor, так что это не синтаксический сахар ctor, а совершенно другой вызов инициализации. Есть ли способ, которым я могу установить значения по умолчанию для некоторых свойств и избежать их инициализации в этой технике?

Ответы [ 3 ]

3 голосов
/ 23 октября 2019

Когда вы пишете:

let obj1: MyClass = { action: "act1" };

Вы используете класс MyClass в качестве типа , в том смысле, что вы говорите компиляторучто переменная obj1 соответствует типу MyClass. Он должен иметь все обязательные поля класса и не может иметь никаких неизвестных свойств.

Это хорошо, потому что, если тип будет иметь 200 свойств, intellisense может подсказать, например, о пропущенных свойствах.

Теперь MyClass на самом деле class, поэтому он работает не только как тип / интерфейс. Он также обладает некоторыми функциональными возможностями, то есть вы можете вызывать конструктор и использовать extends при объявлении класса.

Теперь свойства класса по умолчанию не являются свойствами по умолчанию для типа. Если вы попытаетесь добавить инициализатор в машинописный текст interface или type, вы увидите ошибку;вместо этого, когда вы добавляете свойство по умолчанию в класс, это означает, что экземпляр будет инициализировать это свойство значением по умолчанию только при вызове из конструктора .

Итак, есть некоторыеЧто вы можете сделать, чтобы решить эту проблему:

  1. Вы можете продолжать использовать MyClass в качестве типа в этом сценарии, но тогда вам все равно нужно объявить опору name в литерале объекта:

let obj1: MyClass = {action: "act1", name: "first"};

Если вы сделаете это, вы все равно столкнетесь с:

Литерал объекта может указывать только известные свойства

Поскольку свойство action не существует в MyClass. Вам необходимо добавить свойство action к MyClass.

Использовать конструктор

let obj1 = new MyClass("act1");

Хотя в некоторых сценариях у вас может быть веская причина использовать классы в качестве типов / интерфейсов, вам, вероятно, следует вызывать конструктор классов, когдавозможно - как в этом примере - или, как следует из комментария, использовать для этого интерфейс.

В этом случае, я думаю, вы должны предпочесть вызвать конструктор.

Если вам нужен только тип для получения проверок компилятора / intellisense для типа переменной, вы можете использовать интерфейс:
interface MyCustomType {
  name: string;
  action?: string;
}

Таким образом, вы получите предупреждение, если попытаетесь ввести переменнуюкак MyCustomType без имени:

let obj: MyCustomType = {
  action: 'act1',
} // error, you need to set 'name' since it is a mandatory field

Вы можете установить объект с действием или без действия, так как это необязательно (из-за '?' в объявлении).

Выневозможно добавить неизвестные поля:

let obj: MyCustomType = {
  name: 'name',
  value: 1, // error, unknown field
}
0 голосов
/ 27 октября 2019

Спасибо за все вышеизложенные предложения, я наконец-то нашел решение, которое позволяет мне использовать ctor и по-прежнему получать ошибки любых пропущенных / дополнительных значений И разрешать мне устанавливать значения по умолчанию, которые являются необязательными в инициализаторе литерала объекта "":

class MyClassValues {
    constructor(public name: string, public action?: string) {}
}

class MyClass extends MyClassValues {
    constructor(v: MyClassValues) {
        super(v.name, "default1");
    }
}

let c1 : MyClass = new MyClass({}); // error, missing name
let c2 : MyClass = new MyClass({x:"y"}); // error, unknown prop
let c3 : MyClass = new MyClass({name:"hello"}); // no error
console.log(c3.action); // prints "default1";
0 голосов
/ 23 октября 2019

В вашем коде let obj1: MyClass = { action: "act1" };

Вы не инициализируете obj1 экземпляром MyClass, а вместо этого назначаете объект { action: "act1" } переменной, которая должна иметь тип MyClass. Таким образом, возникает ошибка машинописи.

Правильная реализация:

class MyClass {
    name: string = "myname";
    constructor(public action: string) { 
    }
}

let obj1 = new MyClass("action");
console.log(obj1);

/* 
   outputs:

   {
      action: "action"
      name: "myname"
   }
*/
...