Объявление переменной пользовательского интерфейса Typescript - PullRequest
0 голосов
/ 09 мая 2018

Новичок TypeScript здесь, и в настоящее время я изучаю язык на TutorialsPoint здесь . В настоящее время мне трудно понять разницу между этими двумя частями кода.

interface Person{
    age: number;
}

interface Musician extends Person{
    instrument: string;
}

var drummer:Musician = {
    instrument: "drum",
    age: 28
}

и

interface Person{
    age: number;
}

interface Musician extends Person{
    instrument: string;
}

var drummer = <Musician>{}
drummer.instrument = "drum"
drummer.age = 28

В чем разница между двумя? и есть ли конкретная ситуация, когда лучше использовать первую / вторую реализацию?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

В конце концов, это одно и то же, но первое предпочтительнее, когда это возможно.

В этом случае:

var drummer: Musician = {
    instrument: "drum",
    age: 28
}

вы заявляете, что drummer является Musician, используя аннотацию типа и присваиваете ей литерал объекта. Компилятор рад этому, потому что он может проверить, что да, назначаемый вами литерал объекта совместим с интерфейсом Musician. Он имеет строковое свойство instrument и числовое свойство age.

А что если мы попробуем это:

var drummer: Musician = {};
//  ~~~~~~~ <-- error!
// Type '{}' is not assignable to type 'Musician'.
//  Property 'instrument' is missing in type '{}'.
drummer.instrument = "drum"
drummer.age = 28

Присваивание литерала пустого объекта значению, объявленному как Musician, вызывает ошибку компилятора. В конце концов, пустой литерал объекта не имеет строкового свойства instrument или числового свойства age. И вас предупреждают об этом. Теперь, вы знаете, что следующие две строки решат эту проблему, а компилятор - нет.

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

var drummer = <Musician>{}; // okay
drummer.instrument = "drum"
drummer.age = 28

Утверждение - это то, где вы говорите компилятору "этот объект действительно Musician, хотя сейчас он не похож на него". Вы берете на себя ответственность за обеспечение того, что drummer является Musician, и освобождаете компилятор от ответственности за проверку этого для вас.

И поскольку следующие две строки добавляют необходимые свойства, все в порядке.


Первый вариант предпочтительнее, потому что вы обычно хотите, чтобы компилятор проверял ваши типы, если это возможно. Типовое утверждение отказывается от некоторой безопасности, которая хороша, пока это не так, как вождение автомобиля без ремня безопасности:

var drummer = <Musician>{}; // okay
drummer.age = 28;
// whoops, forgot the instrument, but TypeScript isn't complaining

// ... later ...
console.log(drummer.instrument.toUpperCase()); 
// no error at compile time
// but blows up at runtime

Бывают случаи, когда вам приходится использовать утверждения типа. Например, когда у вас есть какая-то круговая ссылка, где вам нужно построить объект по частям:

interface MarriedPerson extends Person {
  spouse: MarriedPerson
}

var adam: MarriedPerson = {
  age: 0,
  // spouse: eve <-- can't do this before eve is defined
} as MarriedPerson;

var eve: MarriedPerson = {
  age: 0,
  spouse: adam
}

adam.spouse = eve;  // okay now

В приведенном выше примере каждый MarriedPerson нуждается в ссылке на MarriedPerson ... но его не будет, пока вы его не создадите. Таким образом, вы вынуждены прибегнуть к короткому промежутку времени, когда один из MarriedPerson объектов не имеет требуемого spouse. И поэтому требуются утверждения.

Это имеет смысл? Надеюсь, поможет; удачи!

0 голосов
/ 09 мая 2018

Примеры немного отличаются:

  • Сначала вы определяете переменную с типом Musician, а затем присваиваете объект этой переменной, которая соответствует этому типу.
  • Во втором вы определяете переменную без явного типа (что означает, что TypeScript выведет его), создаете пустой объект и затем приводите к этому объекту типа Musicican.
    • Кроме того, предпочтительным синтаксисом для приведения в TypeScript является {} as Musician - используемый вами синтаксис угловой скобки не совместим с расширением синтаксиса JSX, обычно используемым в приложениях React, поэтому его заменили чем-то менее двусмысленным .

Я бы порекомендовал первый пример вместо второго в подавляющем большинстве случаев - пустой объект на самом деле не реализует Musician, поэтому вы фактически обходите проверку типов!

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

interface Person {
    // '?' makes a field optional 
    age?: number;
}

interface Musician extends Person {
    instrument?: string;
}

// The cast can now be replaced with a proper type
var drummer: Musician = {};
drummer.instrument = "drum";
drummer.age = 28;

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

...