Avatar ·

В чем разница между типами String и string в TypeScript?

Привет, коллеги! Я только начал изучать TypeScript и столкнулся с непонятной ситуацией. В некоторых примерах кода я вижу, что для объявления переменной строкового типа используется `string` (с маленькой буквы), а в других — `String` (с большой буквы). Например: ```typescript let name1: string = "John"; let name2: String = "John"; ``` Оба варианта работают, и я не вижу разницы в поведении. Мой код компилируется без ошибок в обоих случаях. Но я чувствую, что это не просто стилистическое различие. Я где-то слышал, что `String` — это класс, а `string` — это примитивный тип, но не понимаю, как это влияет на практическое использование. Может ли кто-нибудь объяснить, в чем именно разница? Когда следует использовать один вариант, а когда другой? Есть ли какие-то подводные камни, если я буду использовать `String` вместо `string`? Буду благодарен за простой пример, демонстрирующий различия. Я уже погуглил, но ответы на английском Stack Overflow слишком сложные для новичка. Хочется получить понятное объяснение на русском с примерами. <<>>

Краткий ответ

Используйте string (с маленькой буквы) всегда, когда объявляете тип переменной. String (с большой буквы) — это встроенный JavaScript-конструктор (класс), который почти никогда не нужен для аннотации типов в TypeScript.

Подробное объяснение

В TypeScript есть два совершенно разных понятия:

  • string — это примитивный тип, обозначающий простую строку. Это литералы, переменные и результаты операций.
  • String — это ссылочный тип (объект-обёртка), который создаётся при вызове new String("...").

Проблема в том, что JavaScript автоматически преобразует примитивные строки в объекты String при вызове методов (например, "hello".toUpperCase()), поэтому новички не замечают разницы. Но в TypeScript эта разница критична.

Пример, показывающий разницу

// Примитивный тип string
let primitiveStr: string = "Hello";
console.log(typeof primitiveStr); // "string"

// Объектный тип String (через конструктор)
let objectStr: String = new String("Hello");
console.log(typeof objectStr); // "object" — это объект, а не строка!

// Сравнение
console.log(primitiveStr === objectStr); // false! Разные типы
console.log(primitiveStr == objectStr);  // true (нестрогое сравнение преобразует объект в примитив)

// Проверка с помощью typeof
if (typeof primitiveStr === "string") { /* true */ }
if (typeof objectStr === "string") { /* false — это object */ }

Почему не стоит использовать String как тип?

  1. Проблемы с присваиванием: если функция ожидает string, а вы передаёте String, TypeScript выдаст ошибку (если включён strict mode).
  2. Ложное чувство безопасности: String может быть null или undefined, а string — нет (если не указано иное).
  3. Производительность: объекты String медленнее и занимают больше памяти.

Когда String может быть полезен?

Практически никогда для типов. Единственный легитимный случай — если вы пишете код, который явно работает с объектами-обёртками (например, расширяете прототип String). Но это считается плохой практикой в современном JavaScript.

Правило для новичков

// ✅ Правильно
let name: string = "John";
function greet(msg: string): void { ... }

// ❌ Неправильно (но технически работает)
let name: String = "John";
function greet(msg: String): void { ... }

Запомните: всегда используйте string для аннотации типов. String оставьте только для вызова статических методов, например String.fromCharCode().

<<>>

Дополнение: как TypeScript обрабатывает несоответствие

Хотя на первый взгляд string и String взаимозаменяемы, TypeScript имеет встроенную защиту. Если вы включите в tsconfig.json опцию "strict": true (а это рекомендуется), то компилятор начнёт различать эти типы в некоторых сценариях.

// В strict mode это вызовет ошибку
function processString(input: string) {
    console.log(input.length);
}

const objStr: String = new String("test");
processString(objStr); // ❌ Error: Argument of type 'String' is not assignable to parameter of type 'string'

Почему это важно для проверки типов?

Представьте, что вы пишете библиотеку и ожидаете string, а пользователь передаёт String. Если вы попытаетесь использовать typeof для проверки, то получите "object", а не "string". Это может привести к багам в runtime.

Практический совет

Если вы видите в чужом коде String как тип — скорее всего, это ошибка или код, написанный начинающим разработчиком. Исправляйте на string. Исключение — если вы работаете с очень старым JavaScript-кодом, где используются объекты-обёртки, но в современном TypeScript это не нужно.

Запомните: примитивные типы в TypeScript пишутся с маленькой буквы: string, number, boolean, symbol, bigint. С большой буквы — это конструкторы, которые не предназначены для аннотации типов.