Как получить имя типа значения строкой в 1С 8.3 и не сломать код

· 9 мин

Содержание

Чтобы получить тип значения строкой, оберните результат в Строка(): Строка(ТипЗнч(Значение)) вернёт, например, Число, Строка или читаемое название ссылочного типа. Но это представление для человека. Для логики кода тип сравнивают с Тип("..."), а для хранения и обмена берут XMLТипЗнч(Значение).ИмяТипа или полное имя объекта метаданных.

Выбор способа зависит от задачи: показать тип пользователю, сохранить его в настройках или построить по нему запрос. Всё относится к платформе 1С:Предприятие 8.3 и не зависит от конфигурации: БП, ЗУП, УТ или своя разработка.

Почему ТипЗнч возвращает не строку

Функция ТипЗнч() возвращает значение типа Тип. Это отдельный объект платформы, а не текст. Его можно сравнить с другим типом, положить в массив или использовать ключом соответствия. Но склеить его со строкой без преобразования нельзя: платформа подставит представление, и вы получите не то, что ожидали.

Что важно знать про значение Тип:

  • 🔹 у него нет свойств вроде Имя или ПолноеИмя — обращение ТипЗнч(Х).Имя даст ошибку «Поле объекта не обнаружено»;
  • 🔹 его представление (Строка()) зависит от языка интерфейса и формулировок платформы;
  • 🔹 для пустого составного реквизита ТипЗнч вернёт Тип("Неопределено"), для NULL из запроса — Тип("Null");
  • 🔹 два типа корректно сравниваются через =, и это самая быстрая проверка.

Отсюда главное правило: строка нужна для вывода пользователю, в лог или для сохранения. Для ветвления кода строка не нужна вообще.

Четыре способа превратить тип значения в строку

У каждого способа своё назначение. Перепутаете — получите код, который работает у вас и падает у коллеги с английским интерфейсом.

СпособЧто вернёт для ссылки на номенклатуруКогда использоватьОграничения
Строка(ТипЗнч(Х))представление типа на языке интерфейсавывод в сообщение, отладканельзя сравнивать с литералом
XMLТипЗнч(Х).ИмяТипаCatalogRef.Номенклатурахранение, обмен, ключи настроекдля несериализуемых типов вернёт Неопределено
Метаданные.НайтиПоТипу(ТипЗнч(Х)).ПолноеИмя()Справочник.Номенклатураработа с метаданными, построение запросовтолько для объектов конфигурации, только на сервере
ЗначениеВСтрокуВнутр(ТипЗнч(Х))внутренняя строка в фигурных скобкахсохранение «как есть» с точным восстановлениемнечитаемо, только сервер и толстый клиент

Строка() — для глаз человека

Самый простой вариант. Подходит для сообщений и записи в журнал регистрации:

Значение = Справочники.Номенклатура.НайтиПоКоду("00-000001");
Сообщить("Тип значения: " + Строка(ТипЗнч(Значение)));

Для примитивов результат предсказуем: Число, Строка, Дата, Булево. Для ссылочных типов текст длиннее, и его точный вид лучше проверить в отладчике на своей платформе, чем закладываться на него в коде.

XMLТипЗнч — стабильное имя для хранения

XMLТипЗнч() возвращает объект ТипДанныхXML с двумя свойствами: ИмяТипа и URIПространстваИмен. Имя типа не зависит от языка интерфейса:

ТипXML = XMLТипЗнч(Значение);
Если ТипXML <> Неопределено Тогда
    ИмяТипа = ТипXML.ИмяТипа; // CatalogRef.Номенклатура, decimal, string, dateTime
КонецЕсли;

Проверка на Неопределено обязательна. Объекты вроде ТаблицаЗначений в форме, ДанныеФормыСтруктура или ОписаниеОповещения не сериализуются в XML, и обращение к .ИмяТипа упадёт.

Метаданные.НайтиПоТипу — имя объекта конфигурации

Если нужно понять, к какому справочнику или документу относится ссылка, идите через метаданные:

МетаОбъект = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));
Если МетаОбъект <> Неопределено Тогда
    ПолноеИмя = МетаОбъект.ПолноеИмя(); // Документ.РеализацияТоваровУслуг
    Имя       = МетаОбъект.Имя;         // РеализацияТоваровУслуг
    Синоним   = МетаОбъект.Синоним;     // то, что видит пользователь
КонецЕсли;

Для примитивных типов функция вернёт Неопределено. Синоним — лучший вариант для вывода пользователю: он задан разработчиком и не содержит служебных слов.

ЗначениеВСтрокуВнутр — точная копия

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

Обратное преобразование: строка в тип

Задача «из строки в тип» встречается так же часто: имя типа хранится в настройках, приходит из файла или собирается по метаданным.

  1. Если в строке имя на встроенном языке — передайте его в Тип(): Тип("СправочникСсылка.Номенклатура"), Тип("Число").
  2. Если храните XML-имя — сохраняйте обе части ТипДанныхXML и восстанавливайте тип через ИзXMLТипа(ИмяТипа, URIПространстваИмен).
  3. Если есть объект метаданных — соберите имя сами: "СправочникСсылка." + МетаОбъект.Имя или "ДокументСсылка." + МетаОбъект.Имя.
// Тип ссылки по полному имени объекта метаданных
Функция ТипСсылкиПоПолномуИмени(ПолноеИмя)
    Части = СтрРазделить(ПолноеИмя, ".");
    Соответствие = Новый Соответствие;
    Соответствие.Вставить("Справочник", "СправочникСсылка");
    Соответствие.Вставить("Документ", "ДокументСсылка");
    Соответствие.Вставить("Перечисление", "ПеречислениеСсылка");
    Соответствие.Вставить("ПланВидовХарактеристик", "ПланВидовХарактеристикСсылка");
    Префикс = Соответствие.Получить(Части[0]);
    Если Префикс = Неопределено Тогда
        Возврат Неопределено;
    КонецЕсли;
    Возврат Тип(Префикс + "." + Части[1]);
КонецФункции

Тип() с несуществующим именем вызывает исключение «Тип не определен». Если строка пришла извне, оберните вызов в Попытка … Исключение.

Где ломается код с типом в виде строки

Большинство проблем с ТипЗнч как строкой — следствие одной привычки: сравнивать текст вместо типов. Разберём симптомы.

Диагностика: выберите симптом

Объект и ссылка — разные типы

Частая ошибка в обработчиках ПередЗаписью и ОбработкаПроведения: сравнивают ТипЗнч(ЭтотОбъект) с типом ссылки. У объекта тип ДокументОбъект.РеализацияТоваровУслуг, у ссылки — ДокументСсылка.РеализацияТоваровУслуг. Условие с неправильным типом никогда не выполнится, а ошибки при этом не будет — код просто молча пропустит ветку.

То же с наборами записей регистров (РегистрНакопленияНаборЗаписей...) и менеджерами (ДокументМенеджер...). Если сомневаетесь, какой тип у переменной, остановитесь в отладчике и посмотрите колонку «Тип» в окне вычисления выражений.

// Неверно: ЭтотОбъект — объект, а не ссылка
Если ТипЗнч(ЭтотОбъект) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда

// Верно: сравниваем тип ссылки объекта
Если ТипЗнч(Ссылка) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда

Ещё одна неочевидная ловушка — склейка типа со строкой без явного Строка(). Выражение "Тип: " + ТипЗнч(Х) отработает, но результат опять будет представлением. Если дальше по коду эту строку разбирают СтрНайти, логика сломается при смене языка или версии платформы.

Скорость в отчётах и обработках

На десятке значений разницы не видно. На обработке, которая обходит 200 000 строк регистра, преобразование типа в строку внутри цикла заметно тормозит.

Что делать в цикле

  • ✅ Создайте типы для сравнения один раз до цикла: ТипРеализация = Тип("ДокументСсылка.РеализацияТоваровУслуг").
  • ✅ Сравнивайте ТипЗнч(Строка.Регистратор) = ТипРеализация — это сравнение двух значений, без построения текста.
  • ✅ Если нужен синоним для вывода, кэшируйте его в Соответствие с ключом-типом и не вызывайте Метаданные.НайтиПоТипу для каждой строки.
  • ❌ Не стройте Строка(ТипЗнч(...)) ради проверки условия.
КэшСинонимов = Новый Соответствие;
Для Каждого СтрокаТЗ Из Таблица Цикл
    ТипРег = ТипЗнч(СтрокаТЗ.Регистратор);
    Синоним = КэшСинонимов.Получить(ТипРег);
    Если Синоним = Неопределено Тогда
        МетаОбъект = Метаданные.НайтиПоТипу(ТипРег);
        Синоним = ?(МетаОбъект = Неопределено, Строка(ТипРег), МетаОбъект.Синоним);
        КэшСинонимов.Вставить(ТипРег, Синоним);
    КонецЕсли;
    СтрокаТЗ.ВидДокумента = Синоним;
КонецЦикла;

Перенос проверки в запрос

Часто анализ типа вообще лучше отдать СУБД. В языке запросов есть ТИПЗНАЧЕНИЯ() и ТИП(), а для ссылок — оператор ССЫЛКА:

ВЫБРАТЬ
    Продажи.Регистратор,
    ВЫБОР
        КОГДА Продажи.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
            ТОГДА "Реализация"
        КОГДА Продажи.Регистратор ССЫЛКА Документ.ВозвратТоваровОтКлиента
            ТОГДА "Возврат"
        ИНАЧЕ "Прочее"
    КОНЕЦ КАК ВидОперации
ИЗ
    РегистрНакопления.Продажи КАК Продажи
ГДЕ
    ТИПЗНАЧЕНИЯ(Продажи.Регистратор) <> ТИП(Документ.КорректировкаРеализации)

Имена документов здесь условные — подставьте объекты своей конфигурации. Такой запрос сразу отдаёт готовую колонку с текстом, и в коде не остаётся цикла по типам. В системе компоновки данных то же выражение ВЫБОР можно задать в вычисляемом поле набора данных.

Примеры из рабочих задач

Универсальная запись в журнал регистрации. Процедура логирования принимает любое значение и пишет его тип. Здесь уместна связка: синоним из метаданных для ссылок, Строка(ТипЗнч()) для остального.

Ключ настроек для составного реквизита. Обработка запоминает, по какому справочнику пользователь фильтровал в прошлый раз. Сохраняйте XMLТипЗнч(Значение).ИмяТипа и URIПространстваИмен — после обновления платформы и смены языка ключ не поменяется.

Динамический запрос по типу ссылки. На вход пришла ссылка неизвестного вида, нужно прочитать её реквизиты:

МетаОбъект = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));
Запрос = Новый Запрос;
Запрос.Текст = СтрШаблон(
    "ВЫБРАТЬ Т.Наименование КАК Наименование ИЗ %1 КАК Т ГДЕ Т.Ссылка = &Ссылка",
    МетаОбъект.ПолноеИмя());
Запрос.УстановитьПараметр("Ссылка", Ссылка);

Если у объекта нет реквизита Наименование (у документов его нет), запрос упадёт. Перед построением текста проверьте Метаданные.Справочники.Содержит(МетаОбъект) или наличие реквизита в МетаОбъект.СтандартныеРеквизиты.

Список допустимых типов составного реквизита. Нужно показать пользователю, что можно выбрать в поле «Документ основание». Берём описание типов из метаданных и собираем строку с синонимами:

ОписаниеТ = Метаданные.Документы.ПоступлениеТоваровУслуг.Реквизиты.ДокументОснование.Тип;
Представления = Новый Массив;
Для Каждого ТекТип Из ОписаниеТ.Типы() Цикл
    МетаОбъект = Метаданные.НайтиПоТипу(ТекТип);
    Представления.Добавить(?(МетаОбъект = Неопределено, Строка(ТекТип), МетаОбъект.Синоним));
КонецЦикла;
Текст = СтрСоединить(Представления, ", ");

Имя документа и реквизита замените на свои. Такой текст удобно вывести в подсказку поля или в сообщение об ошибке заполнения.

Выгрузка в JSON для внешней системы. Принимающей стороне нужен признак вида объекта. Отдавайте МетаОбъект.Имя или XML-имя типа, но не русское представление: его пришлось бы разбирать на другой стороне.

Тип значения в управляемых формах и на клиенте

На клиенте доступны ТипЗнч(), Тип() и сравнение типов. Поэтому проверку вида Если ТипЗнч(Объект.Контрагент) = Тип("СправочникСсылка.Контрагенты") можно оставить в клиентском обработчике ПриИзменении — серверный вызов не нужен.

Что учитывать в формах:

  • 📌 реквизит формы с типом ДанныеФормыСтруктура на клиенте — это не объект справочника, и ТипЗнч вернёт тип данных формы;
  • 📌 Метаданные, ЗначениеВСтрокуВнутр и обход объектов конфигурации — только в процедурах с &НаСервере или в серверном общем модуле;
  • 📌 синоним объекта для заголовка формы выгоднее получить один раз в ПриСозданииНаСервере и положить в реквизит формы;
  • 📌 составной реквизит в поле ввода: проверяйте тип выбранного значения в обработчике ПриИзменении, а не при каждом обращении к полю.

Пример серверной функции, которую вызывают с клиента:

&НаСервереБезКонтекста
Функция ПредставлениеТипа(Значение)
    МетаОбъект = Метаданные.НайтиПоТипу(ТипЗнч(Значение));
    Возврат ?(МетаОбъект = Неопределено, Строка(ТипЗнч(Значение)), МетаОбъект.Синоним);
КонецФункции

&НаСервереБезКонтекста не передаёт на сервер данные формы, поэтому вызов лёгкий.

Когда строка с именем типа не нужна

Иногда задача, которую пытаются решить через ТипЗнч в строку, решается проще.

ЗадачаВместо строки с типом
Проверить, что значение — ссылка на любой справочникСправочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Х))
Проверить, что значение — ссылка на любой документДокументы.ТипВсеСсылки().СодержитТип(ТипЗнч(Х))
Проверить тип на соответствие наборуНовый ОписаниеТипов("Число,Строка").СодержитТип(ТипЗнч(Х))
Привести значение к нужному типуОписаниеТипов.ПривестиЗначение(Х)
Разное поведение для разных документовСоответствие «тип → имя процедуры» вместо цепочки Если по строкам
Проверить на пустое значениеЗначениеЗаполнено(Х)

В типовых конфигурациях на БСП есть готовые функции общего модуля ОбщегоНазначения для проверки ссылочных типов. Перед тем как писать свою, поищите в модуле функцию по слову «Ссылка» — скорее всего, нужная там уже есть.

Частые вопросы

Можно ли получить из типа имя на английском?
Да. XMLТипЗнч(Значение).ИмяТипа возвращает имя с английским префиксом, например CatalogRef.Номенклатура. Сама часть с именем объекта остаётся такой, как её назвал разработчик.
Зависит ли регистр букв в Тип() от написания?
Встроенный язык 1С нечувствителен к регистру в именах, поэтому Тип("число") и Тип("Число") дают один тип. Для единообразия кода пишите так, как в синтакс-помощнике.
Как узнать все типы составного реквизита строкой?
Получите ОписаниеТипов реквизита из метаданных, вызовите .Типы() и пройдите массив, применяя к каждому элементу Строка() или Метаданные.НайтиПоТипу.
Почему ТипЗнч у значения из запроса иногда Null?
При левом соединении поля несовпавших строк приходят как NULL. Обработайте их в запросе функцией ЕСТЬNULL() или проверьте ТипЗнч(Х) = Тип("Null") в коде.
Можно ли использовать тип ключом соответствия?
Да, значение Тип подходит ключом Соответствие. Это удобнее и надёжнее, чем ключ-строка с представлением типа.