ТипЗнч, Тип и ОписаниеТипов: проверяем тип значения во встроенном языке 1С
Содержание
Тип объекта в 1С 8.3 определяют функцией ТипЗнч(Значение) и сравнивают результат с Тип("ИмяТипа"): Если ТипЗнч(Док) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда. В отладчике тип видно сразу — в колонке «Тип» окна «Вычислить выражение» (Shift+F9) и в табло.
Всё остальное — частные случаи этой пары: проверка составного реквизита, вопрос «это вообще ссылка?», безопасное приведение строки к числу, фильтр по типу в запросе. Ниже по каждому — рабочий код и подводные камни, на которых чаще всего спотыкаются при доработке типовых конфигураций.
Функция ТипЗнч: как узнать тип значения в коде
ТипЗнч() принимает любое значение и возвращает объект типа Тип. Сам по себе он мало что говорит — его сравнивают с эталоном.
Значение = 125.5;
Если ТипЗнч(Значение) = Тип("Число") Тогда
Сообщить("Это число");
ИначеЕсли ТипЗнч(Значение) = Тип("Строка") Тогда
Сообщить("Это строка");
КонецЕсли;
Где это нужно чаще всего:
- 📎 Реквизиты составного типа —
Регистраторв регистрах,Субконто1..3в проводках,ДокументОснование. - 📦 Параметры процедур, куда передают то ссылку, то массив ссылок.
- 🔄 Обработчики подписок на события, где
Источник— объекты разных справочников и документов. - 🧾 Результат запроса, в котором поле может прийти как
NULL.
Типичный пример с регистратором:
Регистратор = Выборка.Регистратор;
Если ТипЗнч(Регистратор) = Тип("ДокументСсылка.ПоступлениеТоваровУслуг") Тогда
// обработка поступления
ИначеЕсли ТипЗнч(Регистратор) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
// обработка реализации
КонецЕсли;
Ссылка, объект и данные формы — это разные типы
Здесь путаются даже опытные разработчики. Для одного справочника Номенклатура в коде встречаются минимум три типа:
| Что у вас в руках | Как проверить | Откуда берётся |
|---|---|---|
| Ссылка | Тип("СправочникСсылка.Номенклатура") | реквизиты, запросы, Объект.Ссылка |
| Объект | Тип("СправочникОбъект.Номенклатура") | Ссылка.ПолучитьОбъект(), Справочники.Номенклатура.СоздатьЭлемент(), Источник в подписке ПередЗаписью |
| Данные формы | Тип("ДанныеФормыСтруктура") | реквизит Объект в модуле управляемой формы на клиенте |
В модуле формы ТипЗнч(Объект) вернёт не СправочникОбъект, а ДанныеФормыСтруктура. Проверка = Тип("СправочникОбъект.Номенклатура") всегда даст Ложь. Чтобы получить настоящий объект, на сервере вызовите РеквизитФормыВЗначение("Объект").
Для документов — то же: ДокументСсылка.Имя и ДокументОбъект.Имя. Для регистров сведений — РегистрСведенийНаборЗаписей.Имя и РегистрСведенийМенеджерЗаписи.Имя.
Оператор ЕСТЬ в 1С: чем проверять тип во встроенном языке и в запросах
Разработчики, пришедшие из C# или Java, ищут оператор вида Значение ЕСТЬ Тип. Во встроенном языке 1С такого оператора нет. Слово ЕСТЬ встречается только в языке запросов — в конструкции ЕСТЬ NULL.
В коде модулей роль «оператора типа» играют три приёма.
1. Сравнение ТипЗнч() = Тип() — для одного конкретного типа. Показано выше.
2. ОписаниеТипов.СодержитТип() — для проверки против набора типов:
ДопустимыеТипы = Новый ОписаниеТипов("СправочникСсылка.Контрагенты, СправочникСсылка.ФизическиеЛица");
Если ДопустимыеТипы.СодержитТип(ТипЗнч(Владелец)) Тогда
// контрагент или физлицо
КонецЕсли;
3. ТипВсеСсылки() у менеджера коллекции — ответ на вопрос «это ссылка на любой документ?»:
Если Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
// любой документ
ИначеЕсли Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
// любой справочник
КонецЕсли;
Метод есть и у других коллекций: ПланыВидовХарактеристик, ПланыСчетов, Перечисления, БизнесПроцессы, Задачи.
💡 В конфигурациях на БСП (БП 3.0, ЗУП 3.1, УТ 11) для проверки «ссылка или нет» уже есть готовая функция ОбщегоНазначения.ЭтоСсылка(ТипЗнч(Значение)). Свой велосипед писать не нужно.
Тип в запросе: ССЫЛКА, ТИПЗНАЧЕНИЯ и ЕСТЬ NULL
В языке запросов проверки типов свои:
ВЫБРАТЬ
Хозрасчетный.Регистратор,
ТИПЗНАЧЕНИЯ(Хозрасчетный.Регистратор) КАК ТипРегистратора
ИЗ
РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
ГДЕ
Хозрасчетный.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
| Конструкция | Что делает |
|---|---|
Поле ССЫЛКА Документ.Имя | условие «поле содержит ссылку этого типа» |
ТИПЗНАЧЕНИЯ(Поле) = ТИП(Справочник.Имя) | то же через сравнение типов |
Поле ЕСТЬ NULL | поле пустое из-за левого соединения или отсутствия записи |
ВЫРАЗИТЬ(Поле КАК Справочник.Имя) | приводит составное поле к одному типу |
Обращение к реквизиту через точку у составного поля (Регистратор.Контрагент) заставляет платформу соединять таблицы всех возможных типов. ВЫРАЗИТЬ(Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент оставит одно соединение — запрос заметно облегчится на базах с десятками видов документов.
Функция Тип: имя типа и связь с метаданными
Тип("Строка") строит тип по имени. Имя пишется так, как оно выглядит в синтакс-помощнике: "Число", "Дата", "Булево", "Массив", "Структура", "ТаблицаЗначений", "УникальныйИдентификатор", "СправочникСсылка.Валюты".
Если ошибиться в имени, платформа выдаст Тип не определен с указанием строки — в момент выполнения, а не при синтаксической проверке. Опечатка Тип("СправочникСсылка.Номенклатуры") проживёт в коде до первого запуска ветки.
Обратный путь: от значения к объекту метаданных
Часто нужно не сравнить тип, а узнать, что это за объект: его полное имя, синоним, набор реквизитов.
// По ссылке
ОбъектМД = Ссылка.Метаданные();
// По типу — когда на руках только Тип
ОбъектМД = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));
Если ОбъектМД <> Неопределено Тогда
ПолноеИмя = ОбъектМД.ПолноеИмя(); // "Справочник.Номенклатура"
Синоним = ОбъектМД.Синоним;
КонецЕсли;
Метаданные.НайтиПоТипу() для примитивных типов (Число, Строка) вернёт Неопределено — проверку не пропускайте.
Ещё два способа получить имя типа строкой:
- 🏷️
XMLТипЗнч(Значение).ИмяТипа— стабильное английское имя вродеCatalogRef.Номенклатура. Удобно для логов и обменов. - 🔤
Строка(ТипЗнч(Значение))— представление для пользователя. Оно зависит от синонима и языка, для сравнения в коде его не используйте.
Проверить, к какой коллекции относится объект метаданных, можно через вхождение в неё: Метаданные.Документы.Содержит(ОбъектМД). В БСП для этого есть функции вида ОбщегоНазначения.ЭтоДокумент(ОбъектМД).
Приведение типов: ОписаниеТипов и ПривестиЗначение
Узнать тип — половина дела. Вторая половина — получить значение нужного типа из того, что пришло: строки из файла, ячейки Excel, поля внешней базы.
Функции преобразования Число(), Дата(), Булево() работают жёстко: Число("12,5 руб.") выбросит исключение. Мягкий вариант — ПривестиЗначение():
ТипЧисло = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
Сумма = ТипЧисло.ПривестиЗначение(ЗначениеИзФайла);
// Если строка не преобразуется — получим 0, а не ошибку
Как ведут себя разные способы:
| Способ | Не удалось преобразовать | Квалификаторы |
|---|---|---|
Число(Стр) | исключение | не учитывает |
ОписаниеТипов.ПривестиЗначение(Стр) | пустое значение типа (0, пустая строка, пустая дата) | обрезает строку по длине, округляет по точности |
ВЫРАЗИТЬ в запросе | NULL для неподходящего типа в составном поле | учитывает |
Пустое значение после ПривестиЗначение неотличимо от настоящего нуля. Если для загрузки важно отличить «в файле 0» от «в файле мусор», проверяйте исходную строку отдельно или используйте Число() внутри Попытка.
Проверка совместимости перед записью
Перед присвоением реквизиту составного типа удобно спросить сам реквизит, что он принимает:
ТипРеквизита = Метаданные.Документы.ПоступлениеТоваровУслуг.Реквизиты.ДокументОснование.Тип;
Если ТипРеквизита.СодержитТип(ТипЗнч(Основание)) Тогда
ДокОбъект.ДокументОснование = Основание;
КонецЕсли;
Так же работают определяемые типы: Метаданные.ОпределяемыеТипы.Имя.Тип — это ОписаниеТипов, и СодержитТип() подходит без изменений. Массив всех типов описания возвращает Типы().
Попытка…Исключение как способ определить тип: когда это оправдано
Встречается такой код: обратиться к свойству и, если упадёт, решить, что тип «не тот».
// Плохо
Попытка
Код = Значение.Код;
ЭтоСправочник = Истина;
Исключение
ЭтоСправочник = Ложь;
КонецПопытки;
Почему от этого отказываются:
- 🐢 Исключение — дорогая операция, в цикле по тысячам строк разница с
ТипЗнчвидна на глаз. - 🧨 Ошибка внутри транзакции помечает её как сбойную. Дальше запись падает с
В данной транзакции уже происходили ошибки, хотя исключение вы «поймали». - 🙈 Блок
Исключениеглотает и чужие ошибки: нет прав, битая ссылка, обрыв соединения. Вы примете их за «другой тип».
Где Попытка уместна:
- Преобразование внешних данных, когда нужно поймать именно ошибку формата:
Число(Стр)с записьюОписаниеОшибки()в лог загрузки. - Работа с COM-объектами и внешними компонентами, у которых тип заранее не известен.
- Чтение свойства, которого может не быть, — но здесь лучше обойтись без исключения: заполните структуру через
ЗаполнитьЗначенияСвойств()или проверьте наличие реквизита по метаданным.
// Хорошо: проверяем наличие реквизита по метаданным
ОбъектМД = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));
Если ОбъектМД <> Неопределено И ОбъектМД.Реквизиты.Найти("Организация") <> Неопределено Тогда
Организация = Ссылка.Организация;
КонецЕсли;
Тот же приём выручает в общих модулях, куда приходят ссылки разных видов: проверка по метаданным говорит правду заранее, исключение — только постфактум.
Учтите: Реквизиты.Найти() не видит стандартные реквизиты (Код, Наименование, Владелец) — для них есть коллекция СтандартныеРеквизиты.
Как посмотреть тип объекта в отладчике
В Конфигураторе на платформе 8.3 тип любой переменной виден без строчки кода.
- Поставьте точку останова (
F9) на строке, где переменная уже заполнена. - Запустите отладку (
F5) и дождитесь остановки. - Выделите переменную и нажмите
Shift+F9— откроется окно «Вычислить выражение». В колонке «Тип» стоит точное имя:ДокументСсылка.РеализацияТоваровУслуг,ДанныеФормыСтруктура,Число. - Для постоянного наблюдения перетащите переменную в табло — тип будет обновляться на каждом шаге (
F10,F11).
В поле выражения можно писать код целиком: ТипЗнч(Выборка.Регистратор) = Тип("ДокументСсылка.ПоступлениеТоваровУслуг") сразу покажет Истина или Ложь. Так быстро проверяют, правильно ли написано имя типа, ещё до правки модуля.
💡 Для составных полей раскройте значение в окне — у ссылки видны реквизиты конкретного документа. Это самый быстрый способ понять, почему в ветку Если не заходит выполнение: часто вместо ссылки там Неопределено или NULL.
В 1С:EDT тип показан в панели «Переменные» в режиме отладки, выражения вычисляются в панели «Выражения».
Практические приёмы и частые ошибки
Выносите Тип() из цикла. Строка разбирается при каждом вызове.
ТипРеализация = Тип("ДокументСсылка.РеализацияТоваровУслуг");
Пока Выборка.Следующий() Цикл
Если ТипЗнч(Выборка.Регистратор) = ТипРеализация Тогда
// ...
КонецЕсли;
КонецЦикла;
Проверяйте пустоту отдельно от типа. Пустая ссылка имеет правильный тип: ТипЗнч(Справочники.Номенклатура.ПустаяСсылка()) = Тип("СправочникСсылка.Номенклатура") — это Истина. Если важно, что значение заполнено, добавьте ЗначениеЗаполнено().
Неопределено и NULL — разные вещи.
Неопределено— не заполненный реквизит составного типа, отсутствующий параметр, результат неудачного поиска.NULL— только из запросов. ПроверкаТипЗнч(Х) = Тип("NULL")равносильнаХ = NULL.
Не сравнивайте типы строками. Строка(ТипЗнч(Х)) = "Номенклатура" сломается, как только кто-то поменяет синоним справочника или включит другой язык интерфейса.
Помните про контекст выполнения. В подписке на событие ПередЗаписью параметр Источник — объект, а в обработчике ОбработкаПроведения модуля документа ЭтотОбъект — тоже объект. А вот в обработчике выбора на форме списка приходит ссылка. Одна и та же проверка в разных местах должна сравнивать с разными типами.
Группы справочника — тот же тип. Группа и элемент иерархического справочника имеют один тип ссылки. Отличить их можно только по реквизиту ЭтоГруппа.
Расширения не меняют имя типа. Справочник, заимствованный в расширение, проверяется тем же Тип("СправочникСсылка.Имя"). Собственный объект расширения называют с префиксом, который задан в самом расширении.
| Задача | Чем решать |
|---|---|
| Конкретный тип | ТипЗнч(Х) = Тип("...") |
| Один из нескольких | Новый ОписаниеТипов("...").СодержитТип(ТипЗнч(Х)) |
| Любой документ или справочник | Документы.ТипВсеСсылки().СодержитТип(...) |
| Любая ссылка | ОбщегоНазначения.ЭтоСсылка(ТипЗнч(Х)) (БСП) |
| Полное имя объекта | Метаданные.НайтиПоТипу(ТипЗнч(Х)).ПолноеИмя() |
| Фильтр в запросе | Поле ССЫЛКА Документ.Имя |
| Безопасное приведение | ОписаниеТипов.ПривестиЗначение() |
Частые вопросы
Как определить тип объекта на клиенте, если метаданные там недоступны?
ТипЗнч() и Тип() работают и на клиенте. Для имени объекта метаданных, реквизитов и синонимов передайте ссылку в серверную процедуру модуля формы или общего модуля.Можно ли получить тип по полному имени вида «Справочник.Номенклатура»?
Тип(СтрЗаменить(ПолноеИмя, "Справочник.", "СправочникСсылка.")). Без разбора строк — через пустую ссылку менеджера: ТипЗнч(Справочники[ИмяСправочника].ПустаяСсылка()).Чем ТипЗнч отличается от ТИПЗНАЧЕНИЯ?
ТипЗнч() — функция встроенного языка, работает в модулях. ТИПЗНАЧЕНИЯ() — функция языка запросов, выполняется на стороне СУБД и сравнивается с ТИП(...) внутри текста запроса.Как узнать тип элемента массива или колонки таблицы значений?
ТипЗнч(Массив[0]). Колонки — через свойство ТаблицаЗначений.Колонки.Имя.ТипЗначения: это ОписаниеТипов, у которого есть Типы() и СодержитТип().Почему у колонки таблицы значений тип пустой?
ТипЗначения.Типы() вернёт пустой массив. Задавайте тип при Колонки.Добавить(), иначе таблицу не получится передать в запрос.