Давайте наведем порядок в голове

Языки программирования по типизации делятся на два больших лагеря — типизированные и не типизированные.

Типизированные языки

К типизированным языкам относятся

  • C/C++
  • Python, PHP, Ruby
  • Lua, JavaScript, Action Script

Не типизированные языки

  • Ассемблер
  • Forth
  • Brainfuck

Да-да, именно так. JavaScript, как и многие другие интерпретируемые языки — типизированный. Поэтому ни в коем случае не говорите, что он не типизированный. Особенно на собеседованиях!

В свою очередь, типизированные языки разделяются еще на несколько пересекающихся категорий:

  • Со статической или динамической типизацией.
  • Со строгой или нестрогой типизацией.
  • С явной или неявной типизацией.

Языки со статической типизацией

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

Представители: C/C++, C#, Java.

TypeScript — язык со статической типизацией.

Языки с динамической типизацией

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

Представители: JavaScript, PHP, Python, Ruby…

Строгая типизация (сильная)

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

Представители: Java, Python, Haskell, Lisp…

Кстати TypeScript добавляет строгую типизацию и не позволяет смешивать типы:

// генерит ошибку при неправильных присвоениях типов
let a: Number = 1;
let b: String = 'a';

// Генерит ошибку:
// Operator '+' cannot be applied to types 'Number' and 'String'.
let c = a + b;

Нестрогая типизация (слабая)

Языки с нестрогой типизацией выполняют множество неявных преобразований типов автоматически. Они делают это, даже если может произойти потеря точности или преобразование неоднозначно.

Представители: JavaScript (йаху!), Lua, Visual Basic, PHP…

Явная типизация

В явно типизированных языках тип новых переменных, функций и аргументов нужно задавать явно.

Представители: C++, D, C#…

Кстати TypeScript — язык с явной и неявной строгой типизацией одновременно. Неявная типизация досталась от JS (так как TS — это JS). А вот фича и особенность TS — это его природа явно типизированного языка.

Неявная типизация

В языках с неявной типизацией задачу по указанию типов перекладывают на компилятор/интерпретатор.

Представители: JavaScript (еее!), PHP, Lua, Python (хотя с версии 3 есть аннотации типов, которые как бы добавляют явную типизацию)…

В таких языках, как правило, у объектов существуют специальные методы, вызываемые при приведении к типу. К примеру, в PHP есть метод _toString(), а в JavaScript одноименный метод, но без подчеркивания — toString(). Эти методы вызываются при приведении объекта к строковому типу. Иногда такие методы называют магическими (любые неявные процессы — это всегда магия).

Итог

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

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