Как получить имя типа значения строкой в 1С 8.3 и не сломать код
Содержание
Чтобы получить тип значения строкой, оберните результат в Строка(): Строка(ТипЗнч(Значение)) вернёт, например, Число, Строка или читаемое название ссылочного типа. Но это представление для человека. Для логики кода тип сравнивают с Тип("..."), а для хранения и обмена берут XMLТипЗнч(Значение).ИмяТипа или полное имя объекта метаданных.
Выбор способа зависит от задачи: показать тип пользователю, сохранить его в настройках или построить по нему запрос. Всё относится к платформе 1С:Предприятие 8.3 и не зависит от конфигурации: БП, ЗУП, УТ или своя разработка.
Почему ТипЗнч возвращает не строку
Функция ТипЗнч() возвращает значение типа Тип. Это отдельный объект платформы, а не текст. Его можно сравнить с другим типом, положить в массив или использовать ключом соответствия. Но склеить его со строкой без преобразования нельзя: платформа подставит представление, и вы получите не то, что ожидали.
Что важно знать про значение Тип:
- 🔹 у него нет свойств вроде
ИмяилиПолноеИмя— обращениеТипЗнч(Х).Имядаст ошибку «Поле объекта не обнаружено»; - 🔹 его представление (
Строка()) зависит от языка интерфейса и формулировок платформы; - 🔹 для пустого составного реквизита
ТипЗнчвернётТип("Неопределено"), дляNULLиз запроса —Тип("Null"); - 🔹 два типа корректно сравниваются через
=, и это самая быстрая проверка.
Отсюда главное правило: строка нужна для вывода пользователю, в лог или для сохранения. Для ветвления кода строка не нужна вообще.
Четыре способа превратить тип значения в строку
У каждого способа своё назначение. Перепутаете — получите код, который работает у вас и падает у коллеги с английским интерфейсом.
| Способ | Что вернёт для ссылки на номенклатуру | Когда использовать | Ограничения |
|---|---|---|---|
Строка(ТипЗнч(Х)) | представление типа на языке интерфейса | вывод в сообщение, отладка | нельзя сравнивать с литералом |
XMLТипЗнч(Х).ИмяТипа | CatalogRef.Номенклатура | хранение, обмен, ключи настроек | для несериализуемых типов вернёт Неопределено |
Метаданные.НайтиПоТипу(ТипЗнч(Х)).ПолноеИмя() | Справочник.Номенклатура | работа с метаданными, построение запросов | только для объектов конфигурации, только на сервере |
ЗначениеВСтрокуВнутр(ТипЗнч(Х)) | внутренняя строка в фигурных скобках | сохранение «как есть» с точным восстановлением | нечитаемо, только сервер и толстый клиент |
Строка() — для глаз человека
Самый простой вариант. Подходит для сообщений и записи в журнал регистрации:
Значение = Справочники.Номенклатура.НайтиПоКоду("00-000001");
Сообщить("Тип значения: " + Строка(ТипЗнч(Значение)));
Для примитивов результат предсказуем: Число, Строка, Дата, Булево. Для ссылочных типов текст длиннее, и его точный вид лучше проверить в отладчике на своей платформе, чем закладываться на него в коде.
XMLТипЗнч — стабильное имя для хранения
XMLТипЗнч() возвращает объект ТипДанныхXML с двумя свойствами: ИмяТипа и URIПространстваИмен. Имя типа не зависит от языка интерфейса:
ТипXML = XMLТипЗнч(Значение);
Если ТипXML <> Неопределено Тогда
ИмяТипа = ТипXML.ИмяТипа; // CatalogRef.Номенклатура, decimal, string, dateTime
КонецЕсли;
Проверка на Неопределено обязательна. Объекты вроде ТаблицаЗначений в форме, ДанныеФормыСтруктура или ОписаниеОповещения не сериализуются в XML, и обращение к .ИмяТипа упадёт.
Метаданные.НайтиПоТипу — имя объекта конфигурации
Если нужно понять, к какому справочнику или документу относится ссылка, идите через метаданные:
МетаОбъект = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));
Если МетаОбъект <> Неопределено Тогда
ПолноеИмя = МетаОбъект.ПолноеИмя(); // Документ.РеализацияТоваровУслуг
Имя = МетаОбъект.Имя; // РеализацияТоваровУслуг
Синоним = МетаОбъект.Синоним; // то, что видит пользователь
КонецЕсли;
Для примитивных типов функция вернёт Неопределено. Синоним — лучший вариант для вывода пользователю: он задан разработчиком и не содержит служебных слов.
ЗначениеВСтрокуВнутр — точная копия
Внутренний формат восстанавливается функцией ЗначениеИзСтрокиВнутр() без потерь. Используйте его, когда тип нужно сохранить и потом вернуть ровно тот же. Читать такую строку глазами бессмысленно, а формат не предназначен для обмена с другими системами.
Обратное преобразование: строка в тип
Задача «из строки в тип» встречается так же часто: имя типа хранится в настройках, приходит из файла или собирается по метаданным.
- Если в строке имя на встроенном языке — передайте его в
Тип():Тип("СправочникСсылка.Номенклатура"),Тип("Число"). - Если храните XML-имя — сохраняйте обе части
ТипДанныхXMLи восстанавливайте тип черезИзXMLТипа(ИмяТипа, URIПространстваИмен). - Если есть объект метаданных — соберите имя сами:
"СправочникСсылка." + МетаОбъект.Имяили"ДокументСсылка." + МетаОбъект.Имя.
// Тип ссылки по полному имени объекта метаданных
Функция ТипСсылкиПоПолномуИмени(ПолноеИмя)
Части = СтрРазделить(ПолноеИмя, ".");
Соответствие = Новый Соответствие;
Соответствие.Вставить("Справочник", "СправочникСсылка");
Соответствие.Вставить("Документ", "ДокументСсылка");
Соответствие.Вставить("Перечисление", "ПеречислениеСсылка");
Соответствие.Вставить("ПланВидовХарактеристик", "ПланВидовХарактеристикСсылка");
Префикс = Соответствие.Получить(Части[0]);
Если Префикс = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
Возврат Тип(Префикс + "." + Части[1]);
КонецФункции
Тип() с несуществующим именем вызывает исключение «Тип не определен». Если строка пришла извне, оберните вызов в Попытка … Исключение.
Где ломается код с типом в виде строки
Большинство проблем с ТипЗнч как строкой — следствие одной привычки: сравнивать текст вместо типов. Разберём симптомы.
Объект и ссылка — разные типы
Частая ошибка в обработчиках ПередЗаписью и ОбработкаПроведения: сравнивают ТипЗнч(ЭтотОбъект) с типом ссылки. У объекта тип ДокументОбъект.РеализацияТоваровУслуг, у ссылки — ДокументСсылка.РеализацияТоваровУслуг. Условие с неправильным типом никогда не выполнится, а ошибки при этом не будет — код просто молча пропустит ветку.
То же с наборами записей регистров (РегистрНакопленияНаборЗаписей...) и менеджерами (ДокументМенеджер...). Если сомневаетесь, какой тип у переменной, остановитесь в отладчике и посмотрите колонку «Тип» в окне вычисления выражений.
// Неверно: ЭтотОбъект — объект, а не ссылка
Если ТипЗнч(ЭтотОбъект) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
// Верно: сравниваем тип ссылки объекта
Если ТипЗнч(Ссылка) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
Ещё одна неочевидная ловушка — склейка типа со строкой без явного Строка(). Выражение "Тип: " + ТипЗнч(Х) отработает, но результат опять будет представлением. Если дальше по коду эту строку разбирают СтрНайти, логика сломается при смене языка или версии платформы.
Скорость в отчётах и обработках
На десятке значений разницы не видно. На обработке, которая обходит 200 000 строк регистра, преобразование типа в строку внутри цикла заметно тормозит.
Что делать в цикле
- ✅ Создайте типы для сравнения один раз до цикла:
ТипРеализация = Тип("ДокументСсылка.РеализацияТоваровУслуг"). - ✅ Сравнивайте
ТипЗнч(Строка.Регистратор) = ТипРеализация— это сравнение двух значений, без построения текста. - ✅ Если нужен синоним для вывода, кэшируйте его в
Соответствиес ключом-типом и не вызывайтеМетаданные.НайтиПоТипудля каждой строки. - ❌ Не стройте
Строка(ТипЗнч(...))ради проверки условия.
КэшСинонимов = Новый Соответствие;
Для Каждого СтрокаТЗ Из Таблица Цикл
ТипРег = ТипЗнч(СтрокаТЗ.Регистратор);
Синоним = КэшСинонимов.Получить(ТипРег);
Если Синоним = Неопределено Тогда
МетаОбъект = Метаданные.НайтиПоТипу(ТипРег);
Синоним = ?(МетаОбъект = Неопределено, Строка(ТипРег), МетаОбъект.Синоним);
КэшСинонимов.Вставить(ТипРег, Синоним);
КонецЕсли;
СтрокаТЗ.ВидДокумента = Синоним;
КонецЦикла;
Перенос проверки в запрос
Часто анализ типа вообще лучше отдать СУБД. В языке запросов есть ТИПЗНАЧЕНИЯ() и ТИП(), а для ссылок — оператор ССЫЛКА:
ВЫБРАТЬ
Продажи.Регистратор,
ВЫБОР
КОГДА Продажи.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
ТОГДА "Реализация"
КОГДА Продажи.Регистратор ССЫЛКА Документ.ВозвратТоваровОтКлиента
ТОГДА "Возврат"
ИНАЧЕ "Прочее"
КОНЕЦ КАК ВидОперации
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
ТИПЗНАЧЕНИЯ(Продажи.Регистратор) <> ТИП(Документ.КорректировкаРеализации)
Имена документов здесь условные — подставьте объекты своей конфигурации. Такой запрос сразу отдаёт готовую колонку с текстом, и в коде не остаётся цикла по типам. В системе компоновки данных то же выражение ВЫБОР можно задать в вычисляемом поле набора данных.
Примеры из рабочих задач
Универсальная запись в журнал регистрации. Процедура логирования принимает любое значение и пишет его тип. Здесь уместна связка: синоним из метаданных для ссылок, Строка(ТипЗнч()) для остального.
Ключ настроек для составного реквизита. Обработка запоминает, по какому справочнику пользователь фильтровал в прошлый раз. Сохраняйте XMLТипЗнч(Значение).ИмяТипа и URIПространстваИмен — после обновления платформы и смены языка ключ не поменяется.
Динамический запрос по типу ссылки. На вход пришла ссылка неизвестного вида, нужно прочитать её реквизиты:
МетаОбъект = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));
Запрос = Новый Запрос;
Запрос.Текст = СтрШаблон(
"ВЫБРАТЬ Т.Наименование КАК Наименование ИЗ %1 КАК Т ГДЕ Т.Ссылка = &Ссылка",
МетаОбъект.ПолноеИмя());
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Если у объекта нет реквизита Наименование (у документов его нет), запрос упадёт. Перед построением текста проверьте Метаданные.Справочники.Содержит(МетаОбъект) или наличие реквизита в МетаОбъект.СтандартныеРеквизиты.
Список допустимых типов составного реквизита. Нужно показать пользователю, что можно выбрать в поле «Документ основание». Берём описание типов из метаданных и собираем строку с синонимами:
ОписаниеТ = Метаданные.Документы.ПоступлениеТоваровУслуг.Реквизиты.ДокументОснование.Тип;
Представления = Новый Массив;
Для Каждого ТекТип Из ОписаниеТ.Типы() Цикл
МетаОбъект = Метаданные.НайтиПоТипу(ТекТип);
Представления.Добавить(?(МетаОбъект = Неопределено, Строка(ТекТип), МетаОбъект.Синоним));
КонецЦикла;
Текст = СтрСоединить(Представления, ", ");
Имя документа и реквизита замените на свои. Такой текст удобно вывести в подсказку поля или в сообщение об ошибке заполнения.
Выгрузка в JSON для внешней системы. Принимающей стороне нужен признак вида объекта. Отдавайте МетаОбъект.Имя или XML-имя типа, но не русское представление: его пришлось бы разбирать на другой стороне.
Тип значения в управляемых формах и на клиенте
На клиенте доступны ТипЗнч(), Тип() и сравнение типов. Поэтому проверку вида Если ТипЗнч(Объект.Контрагент) = Тип("СправочникСсылка.Контрагенты") можно оставить в клиентском обработчике ПриИзменении — серверный вызов не нужен.
Что учитывать в формах:
- 📌 реквизит формы с типом
ДанныеФормыСтруктурана клиенте — это не объект справочника, иТипЗнчвернёт тип данных формы; - 📌
Метаданные,ЗначениеВСтрокуВнутри обход объектов конфигурации — только в процедурах с&НаСервереили в серверном общем модуле; - 📌 синоним объекта для заголовка формы выгоднее получить один раз в
ПриСозданииНаСервереи положить в реквизит формы; - 📌 составной реквизит в поле ввода: проверяйте тип выбранного значения в обработчике
ПриИзменении, а не при каждом обращении к полю.
Пример серверной функции, которую вызывают с клиента:
&НаСервереБезКонтекста
Функция ПредставлениеТипа(Значение)
МетаОбъект = Метаданные.НайтиПоТипу(ТипЗнч(Значение));
Возврат ?(МетаОбъект = Неопределено, Строка(ТипЗнч(Значение)), МетаОбъект.Синоним);
КонецФункции
&НаСервереБезКонтекста не передаёт на сервер данные формы, поэтому вызов лёгкий.
Когда строка с именем типа не нужна
Иногда задача, которую пытаются решить через ТипЗнч в строку, решается проще.
| Задача | Вместо строки с типом |
|---|---|
| Проверить, что значение — ссылка на любой справочник | Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Х)) |
| Проверить, что значение — ссылка на любой документ | Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Х)) |
| Проверить тип на соответствие набору | Новый ОписаниеТипов("Число,Строка").СодержитТип(ТипЗнч(Х)) |
| Привести значение к нужному типу | ОписаниеТипов.ПривестиЗначение(Х) |
| Разное поведение для разных документов | Соответствие «тип → имя процедуры» вместо цепочки Если по строкам |
| Проверить на пустое значение | ЗначениеЗаполнено(Х) |
В типовых конфигурациях на БСП есть готовые функции общего модуля ОбщегоНазначения для проверки ссылочных типов. Перед тем как писать свою, поищите в модуле функцию по слову «Ссылка» — скорее всего, нужная там уже есть.
Частые вопросы
Можно ли получить из типа имя на английском?
XMLТипЗнч(Значение).ИмяТипа возвращает имя с английским префиксом, например CatalogRef.Номенклатура. Сама часть с именем объекта остаётся такой, как её назвал разработчик.Зависит ли регистр букв в Тип() от написания?
Тип("число") и Тип("Число") дают один тип. Для единообразия кода пишите так, как в синтакс-помощнике.Как узнать все типы составного реквизита строкой?
ОписаниеТипов реквизита из метаданных, вызовите .Типы() и пройдите массив, применяя к каждому элементу Строка() или Метаданные.НайтиПоТипу.Почему ТипЗнч у значения из запроса иногда Null?
NULL. Обработайте их в запросе функцией ЕСТЬNULL() или проверьте ТипЗнч(Х) = Тип("Null") в коде.Можно ли использовать тип ключом соответствия?
Тип подходит ключом Соответствие. Это удобнее и надёжнее, чем ключ-строка с представлением типа.