Чем отличаются типы String и string в TypeScript?
Ключевое отличие: примитив vs объект-обёртка
В TypeScript (и JavaScript) есть фундаментальное различие между string (строчная) и String (заглавная). Первое — это тип примитива, второе — тип объекта-обёртки (wrapper object).
Что такое string (строчная)?
Это примитивный тип данных. Когда вы пишете:
let name: string = "Alice";
вы создаёте примитивную строку. Она легковесна, неизменяема и хранится в стеке. Примитивные строки всегда сравниваются по значению:
let a: string = "hello";
let b: string = "hello";
console.log(a === b); // true — сравниваются значения
Что такое String (заглавная)?
Это тип, соответствующий встроенному объекту String из JavaScript. Когда вы используете конструктор new String(), вы создаёте объект:
let obj: String = new String("Hello");
console.log(typeof obj); // "object" — это объект, а не примитив!
Объекты String сравниваются по ссылке, а не по значению:
let x: String = new String("hello");
let y: String = new String("hello");
console.log(x === y); // false — разные объекты в памяти
Почему код иногда работает с String?
JavaScript автоматически «оборачивает» примитивные строки в объекты String, когда вы вызываете методы (например, .toUpperCase()). Это называется autoboxing. Поэтому:
let str: string = "hello";
console.log(str.toUpperCase()); // Работает — JS временно создаёт объект-обёртку
Однако обратное не всегда верно. Объект String не всегда автоматически преобразуется в примитив. Например, при сложении:
let greeting: String = new String("Hello");
let message: string = "World";
let result = greeting + message; // Работает — JS вызывает .toString() у объекта
// Но TypeScript может ругаться на несоответствие типов
Практические проблемы с String
- Сравнение:
new String("a") === new String("a")даётfalse, что часто приводит к багам. - Типобезопасность: Функции, ожидающие
string, не примутStringбез явного преобразования. - Производительность: Объекты
Stringсоздаются в куче и требуют больше памяти, чем примитивы.
Правило большого пальца
Всегда используйте строчную string. TypeScript включает String только для совместимости с JavaScript и для случаев, когда вам действительно нужен объект-обёртка (что бывает крайне редко — например, для работы с String.prototype в метапрограммировании).
Вот безопасный код:
// ✅ Правильно
let firstName: string = "John";
let lastName: string = "Doe";
let fullName: string = `${firstName} ${lastName}`;
let isEqual: boolean = (firstName === "John"); // true
// ❌ Избегайте
let badName: String = new String("John");
let badCheck: boolean = (badName === new String("John")); // false — баг!
Если вы видите String в чужом коде (особенно в интерфейсах или типах), это почти наверняка ошибка или устаревший код. Исправляйте на string.
То же самое касается Number/number, Boolean/boolean и Symbol/symbol — всегда выбирайте строчные варианты.
Дополнение: когда String может быть полезен?
Хотя в 99.9% случаев нужно использовать string, есть редкие сценарии, где объект String оправдан:
- Метапрограммирование: Если вы расширяете прототип
Stringсвоими методами (хотя это считается плохой практикой). - Сериализация: В некоторых библиотеках для работы с JSON или базами данных объекты
Stringмогут вести себя иначе при сериализации. - TypeScript типы: Иногда вы можете встретить
Stringв типах сторонних библиотек (например,String | null). Это обычно legacy-код, который стоит заменить наstring | null.
Однако на практике эти случаи настолько редки, что лучше придерживаться правила: если вы не уверены — используйте string. Это сделает ваш код предсказуемым, производительным и совместимым с большинством TypeScript-проектов.
Если вы встретили String в коде коллеги — вежливо укажите на разницу и предложите исправить. Это убережёт команду от трудноуловимых багов со сравнением объектов.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги
Микросервисы на Kotlin: архитектура и практика