Как не надо учить TypeScript

0 150

Ошибка 1: Игнорирование JavaScript

TypeScript — это надмножество JavaScript, и с тех пор его так и рекламируют. Это означает, что JavaScript в значительной степени является частью языка. Все это так. Выбор TypeScript не дает вам возможности отказаться от JavaScript и его неустойчивого поведения. Но TypeScript упрощает его понимание. И вы можете видеть, как JavaScript прорывается повсюду.

Было бы очень хорошо обрабатывать ошибки так, как вы привыкли в других языках программирования:

JavaScript try { // something with Axios, for example } catch(e: AxiosError) { // ^^^^^^^^^^ Error 1196 }

12345 try {  // something with Axios, for example} catch(e: AxiosError) {//         ^^^^^^^^^^ Error 1196}

Как не надо учить TypeScript

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Но это невозможно. И причина в том, как работают ошибки JavaScript. Код, который имел бы смысл в TypeScript, но не выполним в JavaScript.

Другой пример: использование Object.keys и ожидание простого доступа к свойствам также может вызвать проблемы.

JavaScript type Person = { name: string, age: number, id: number, } declare const me: Person; Object.keys(me).forEach(key => { // the next line throws red squigglies at us console.log(me[key]) })

123456789 type Person = {  name: string, age: number, id: number,}declare const me: Person; Object.keys(me).forEach(key => {  // the next line throws red squigglies at us  console.log(me[key])})

Существует способ исправления такого поведения, подробно описанный здесь, но его нельзя применять к каждому сценарию. TypeScript просто не может гарантировать, основываясь на вашем коде, что типы доступа к этому свойству будут такими, как вы ожидаете. Код, который отлично работает только на JavaScript, но который трудно выразить с помощью системы типов по многим причинам.

Если вы изучаете TypeScript без какого-либо опыта работы с JavaScript, учитесь различать JavaScript и систему типов. Кроме того, научитесь искать правильные вещи. Именованные параметры в функциях. Вы можете сделать это с объектами в качестве аргументов. Хороший паттерн. Однако это часть JavaScript. Условная последовательность? Сначала она реализована в компиляторе TypeScript, но это также функция JavaScript. Классы и расширение классов? JavaScript. Приватные поля класса? Также JavaScript.

Программный код, который действительно что-то делает, большей частью относится к JavaScript. Недавно на веб-сайте TypeScript появилось гораздо более четкое заявление о том, что значит использовать TypeScript: TypeScript — это JavaScript с синтаксисом для типов. Здесь вся суть! TypeScript — это JavaScript. Понимание JavaScript является ключом к пониманию TypeScript.

Ошибка 2: Аннотирование всего

Аннотация типа — это способ явно указать, какие типы следует ожидать. Вам знакомы случаи, которые очень характерны другим языкам программирования, где многословие StringBuilder stringBuilder = new StringBuilder() гарантирует, что вы действительно имеете дело с типом StringBuilder. Противоположным является вывод типа, когда TypeScript пытается определить тип для вас. let a_number = 2 имеет тип number.

Аннотации типов также являются наиболее очевидным и заметным отличием синтаксиса между TypeScript и JavaScript. Когда вы начнете изучать TypeScript, вам возможно захочется аннотировать все, чтобы выразить ожидаемые типы. Это может показаться очевидным выбором при начале работы с TypeScript, но я умоляю вас экономно использовать аннотации и позволить TypeScript определять типы за вас. Почему? Позвольте мне объяснить, что такое аннотация типа.

Аннотация типа — это способ указать, какие контракты должны быть проверены. Если вы добавляете аннотацию типа к объявлению переменной, вы указываете компилятору проверять соответствие типов во время присваивания.

JavaScript type Person = { name: string, age: number } const me: Person = createPerson()

123456 type Person = {  name: string,  age: number} const me: Person = createPerson()

Если createPerson возвращает что-то, что несовместимо с Person, TypeScript выдаст ошибку. Используйте это, если вы действительно хотите быть уверены, что имеете дело с правильным типом.

Кроме того, с этого момента me имеет тип Person, и TypeScript будет рассматривать его как файл Person. Если в me, например, есть еще свойство profession, TypeScript не позволит вам получить к нему доступ, ибо оно не определено в Person.

Если вы добавляете аннотацию типа к возвращаемому значению сигнатуры функции, вы указываете компилятору проверять, соответствуют ли типы в тот момент, когда вы возвращаете это значение.

JavaScript function createPerson(): Person { return { name: «Stefan», age: 39 } }

123 function createPerson(): Person {  return { name: «Stefan», age: 39 }}

Если я верну что-то, что не соответствует Person, TypeScript выдаст ошибку. Используйте это, если вы хотите быть полностью уверены, что возвращаете правильный тип. Это особенно удобно, если вы работаете с функциями, которые создают большие объекты из различных источников.

Если вы добавляете аннотацию типа к параметрам сигнатуры функции, вы указываете компилятору проверять соответствие типов в тот момент, когда вы передаете аргументы.

JavaScript function printPerson(person: Person) { console.log(person.name, person.age) } printPerson(me)

12345 function printPerson(person: Person) {  console.log(person.name, person.age)} printPerson(me)

На мой взгляд, это самая важная и неизбежная аннотация типа. Все остальное можно предположить.

JavaScript type Person = { name: string, age: number } // Inferred! // return type is { name: string, age: number } function createPerson() { return { name: «Stefan», age: 39} } // Inferred! // me is type of { name: string, age: number} const me = createPerson() // Annotated! You have to check if types are compatible function printPerson(person: Person) { console.log(person.name, person.age) } // All works printPerson(me)

12345678910111213141516171819202122 type Person = {  name: string,  age: number} // Inferred!// return type is { name: string, age: number }function createPerson() {   return { name: «Stefan», age: 39}} // Inferred!// me is type of { name: string, age: number}const me = createPerson()  // Annotated! You have to check if types are compatiblefunction printPerson(person: Person) {  console.log(person.name, person.age)} // All worksprintPerson(me)

Всегда используйте аннотации типов с параметрами функций. Тут вы должны проверить соответствие типу. Это не только намного удобнее, но и дает массу преимуществ. Вы получаете, например, полиморфизм бесплатно.

JavaScript type Person = { name: string, age: number } type Studying = { semester: number } type Student = { id: string, age: number, semester: number } function createPerson() { return { name: «Stefan», age: 39, semester: 25, id: «XPA»} } function printPerson(person: Person) { console.log(person.name, person.age) } function studyForAnotherSemester(student: Studying) { student.semester++ } function isLongTimeStudent(student: Student) { return student.age — student.semester / 2 > 30 && student.semester > 20 } const me = createPerson() // All work! printPerson(me) studyForAnotherSemester(me) isLongTimeStudent(me)

12345678910111213141516171819202122232425262728293031323334353637 type Person = {  name: string,  age: number} type Studying = {  semester: number} type Student = {  id: string,  age: number,  semester: number} function createPerson() {   return { name: «Stefan», age: 39, semester: 25, id: «XPA»}} function printPerson(person: Person) {  console.log(person.name, person.age)} function studyForAnotherSemester(student: Studying) {  student.semester++} function isLongTimeStudent(student: Student) {  return student.age — student.semester / 2 > 30 && student.semester > 20} const me = createPerson()  // All work!printPerson(me)studyForAnotherSemester(me)isLongTimeStudent(me)

Student, Person и Studying имеют некоторое сходство, но не связаны друг с другом. createPerson возвращает то, что совместимо со всеми тремя типами. Если бы мы аннотировали слишком много, нам пришлось бы создавать гораздо больше типов и гораздо больше проверок, чем необходимо, без какой-либо пользы.

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

Ошибка 3: Ошибки типов значений

TypeScript — это расширенный набор JavaScript, что означает, что он добавляет больше возможностей к уже существующему и определенному языку. Со временем вы научитесь определять, какие части — это JavaScript, а какие — TypeScript.

Это действительно помогает рассматривать TypeScript как дополнительный уровень типов по сравнению с обычным JavaScript. Тонкий слой метаинформации, который будет снят перед тем, как ваш код JavaScript запустится в одной из доступных сред выполнения. Некоторые люди даже говорят о том, что код TypeScript «трансформируется в JavaScript» после компиляции.

TypeScript, являющийся неким слоем поверх JavaScript, также означает, что разный синтаксис влияет на разные уровни. В то время как function или const создает имя в JavaScript, объявления type или interface способствует именованию в TypeScript. Например:

Как не надо учить TypeScript

Фреймворк VUE JS: быстрый старт, первые результаты

Получите бесплатный курс и узнайте, как создать веб-приложение на трендовой Frontend-технологии VUE JS с полного нуля

JavaScript // Collection is in TypeScript land! —> type type Collection<T> = { entries: T[] } // printCollection is in JavaScript land! —> value function printCollection(coll: Collection<unknown>) { console.log(…coll.entries) }

123456789 // Collection is in TypeScript land! —> typetype Collection<T> = {  entries: T[]} // printCollection is in JavaScript land! —> valuefunction printCollection(coll: Collection<unknown>) {  console.log(…coll.entries)}

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

JavaScript // a value const person = { name: «Stefan» } // a type type Person = typeof person;

1234567 // a valueconst person = {  name: «Stefan»} // a typetype Person = typeof person;

Typeof создает имя, доступное в слое типов, из слоя значений ниже. Раздражает, когда есть декларация типов, которые создают как типы, так и значения. Например, классы можно использовать в слое TypeScript как тип, а в JavaScript — как значение.

JavaScript // declaration class Person { name: string constructor(n: string) { this.name = n } } // value const person = new Person(«Stefan») // type type PersonCollection = Collection<Person> function printPersons(coll: PersonCollection) { //… }

123456789101112131415161718 // declarationclass Person {  name: string   constructor(n: string) {    this.name = n  }} // valueconst person = new Person(«Stefan») // typetype PersonCollection = Collection<Person> function printPersons(coll: PersonCollection) {  //…}

Обычно мы определяем классы, типы, интерфейсы, перечисления и т. д. с заглавной буквы. И даже если они могут присваивать значения, они точно объявляют типы. Ну, по крайней мере, до тех пор, пока вы не напишете функции в верхнем регистре для своего приложения React.

Если вы привыкли использовать имена в качестве типов и значений, вы очень удивитесь, если вдруг получите ошибку TS2749: ‘YourType’ ссылается на значение, но используется как тип.

JavaScript type PersonProps = { name: string } function Person({ name }: PersonProps) { return <p>{name}</p> } type Collection<T> = { entries: T } type PrintComponentProps = { collection: Collection<Person> // ERROR! // ‘Person’ refers to a value, but is being used as a type }

12345678910111213141516 type PersonProps = {  name: string} function Person({ name }: PersonProps) {  return <p>{name}</p>} type Collection<T> = {  entries: T} type PrintComponentProps = {  collection: Collection<Person> // ERROR!   // ‘Person’ refers to a value, but is being used as a type}

Вот где TypeScript может стать действительно запутанным. Что такое тип, что такое значение, зачем нужно их разделять, почему это не работает, а как в других языках программирования? Внезапно вы видите, что сталкиваетесь с вызовами typeof или даже с вспомогательным типом InstanceType, потому что понимаете, что классы на самом деле предоставляют два типа.

Так что нужно понимать, что предоставляет типы, а что — значения. Каковы границы, как и в каком направлении мы можем двигаться, и что это значит для вашего языка программирования? Эта таблица, адаптированная из документов TypeScript, хорошо подводит итог:

Как не надо учить TypeScript

При изучении TypeScript, вероятно, будет хорошей идеей сосредоточиться на функциях, переменных и простых псевдонимах типов (или интерфейсах, если вам это больше нравится). Это должно дать вам хорошее представление о том, что происходит на уровне типов и что происходит на уровне значений.

Ошибка 4: Идти ва-банк в начале

Мы много говорили о том, какие ошибки может совершить человек, перейдя на TypeScript с другого языка программирования. Справедливости ради, это был мой хлеб с маслом в течение достаточно долгого времени. Но есть и другая позиция: люди, которые много писали на JavaScript, внезапно сталкиваются с другим, иногда очень раздражающим инструментом.

Вы знаете свою кодовую базу как свои пять пальцев, и вдруг компилятор говорит вам, что он не понимает вещей слева и справа, и что вы допустили ошибки, хотя знаете, что ваше программное обеспечение будет работать нормально.

Предполагается, что TypeScript поможет вам быть более продуктивным, но все, что он делает, — это бросает отвлекающие красные волнистые линии под ваш код. Мы все это ощущали, не так ли?

И как относиться к этому! TypeScript может быть очень громоздким, особенно если вы «просто включите его» в существующей кодовой базе JavaScript. TypeScript хочет получить представление обо всем вашем приложении, и для этого вам нужно аннотировать все, чтобы контракты согласовывались. Как громоздко.

Если вы пришли из JavaScript, я бы сказал, что вам следует использовать функции постепенного внедрения TypeScript. TypeScript был разработан для того, чтобы вам было как можно проще адаптироваться, прежде чем идти ва-банк:

Возьмите части своего приложения и перенесите их на TypeScript вместо того, чтобы переносить все. TypeScript совместим с JavaScript (allowJS)

TypeScript выдает скомпилированный код JavaScript, даже если TypeScript находит ошибки в вашем коде. Вы должны отключить явное прерывание кода с помощью флага noEmitOnError. Это позволяет вам по-прежнему работать, даже если ваш компилятор выдает ошибки.

Используйте TypeScript, написав файлы объявления типов и импортировав их через JSDoc. Это хороший первый шаг к получению дополнительной информации о том, что происходит внутри вашей кодовой базы.

Не дойтесь использования any. Вопреки распространенному мнению, использование any абсолютно допустимо, если any используется явным образом.

Ознакомьтесь с документацией по tsconfig, чтобы узнать, какие флаги конфигурации доступны. TypeScript был разработан для постепенного внедрения. Вы можете использовать столько типов, сколько хотите. Вы можете оставить большие части своего приложения в JavaScript, и это определенно должно помочь вам начать работу.

Изучая TypeScript в качестве разработчика JavaScript, не требуйте от себя слишком многого. Попробуйте использовать его как встроенную документацию, чтобы лучше понимать свой код и расширять/улучшать его.

Ошибка 5: Изучение неправильного TypeScript

Если ваш код должен использовать одно из следующих ключевых слов, вы, вероятно, либо находитесь не в том углу TypeScript, либо намного дальше, чем вам хотелось бы:

namespace

declare

module

<reference>

abstract

unique

Это не означает, что эти ключевые слова не вносят важного вклада для различных вариантов использования. Однако при изучении TypeScript вам не следует работать с ними в начале. И это все!

Автор: Stefan Baumgartner

Источник: webformyself.com

Оставьте ответ

Ваш электронный адрес не будет опубликован.