Проверка типа переменной во встроенном языке 1С:Предприятия 8.3
Содержание
Тип значения в 1С 8.3 определяют функцией ТипЗнч(Значение), а сравнивают результат с Тип("ИмяТипа"): Если ТипЗнч(Х) = Тип("Число") Тогда. Это основной способ, он работает на клиенте и на сервере. Для составных типов есть объект ОписаниеТипов, для имени типа строкой — XMLТип() и Метаданные.НайтиПоТипу(), для запросов — ТИПЗНАЧЕНИЯ() и ССЫЛКА.
Какой способ выбрать, зависит от задачи. Проверить одну переменную — хватит ТипЗнч. Проверить, входит ли тип в набор из десяти документов, — удобнее ОписаниеТипов.СодержитТип(). Записать тип в файл или передать в обмен — нужен XMLТип. Всё это общее для платформы и не зависит от конфигурации: код одинаково работает в Бухгалтерии, ЗУП, УТ и в своей разработке.
Что возвращают ТипЗнч и Тип
ТипЗнч() принимает любое значение и возвращает объект типа Тип. Это не строка и не число, а отдельный объект платформы, который умеет только одно: сравниваться с другим таким же объектом.
Тип() делает обратное: по имени типа строкой создаёт тот же объект Тип. Имя пишется так, как оно выглядит в синтакс-помощнике и в свойствах реквизита.
| Что проверяем | Строка для Тип() |
|---|---|
| Число | Тип("Число") |
| Строка | Тип("Строка") |
| Дата | Тип("Дата") |
| Булево | Тип("Булево") |
| Пустое значение | Тип("Неопределено") |
| NULL из запроса | Тип("NULL") |
| Ссылка на справочник | Тип("СправочникСсылка.Номенклатура") |
| Объект справочника | Тип("СправочникОбъект.Номенклатура") |
| Ссылка на документ | Тип("ДокументСсылка.РеализацияТоваровУслуг") |
| Перечисление | Тип("ПеречислениеСсылка.ВидыКонтрагентов") |
| Коллекции | Тип("Массив"), Тип("Структура"), Тип("ТаблицаЗначений") |
Имена справочников, документов и перечислений в таблице — для примера. Подставляйте имена объектов из своей конфигурации, ровно как в дереве метаданных.
Ссылка и объект — разные типы. ТипЗнч(Ссылка) вернёт СправочникСсылка.Номенклатура, а ТипЗнч(Ссылка.ПолучитьОбъект()) — СправочникОбъект.Номенклатура. Путаница здесь — частая причина условий, которые «никогда не срабатывают».
Если в Тип() передать имя, которого нет в конфигурации, платформа вызовет исключение. Когда имя приходит извне (из настроек, файла, параметра), оберните вызов:
Попытка
ИскомыйТип = Тип(ИмяТипаСтрокой);
Исключение
ИскомыйТип = Неопределено;
КонецПопытки;
Как сравнить типы и почему в 1С нет оператора ЕСТЬ
Во встроенном языке 1С нет оператора вроде is или instanceof. Тип проверяют только сравнением двух объектов Тип через = или <>:
Если ТипЗнч(Значение) = Тип("Число") Тогда
Сумма = Сумма + Значение;
ИначеЕсли ТипЗнч(Значение) = Тип("Строка") Тогда
Текст = Текст + Значение;
КонецЕсли;
Слово ЕСТЬ в 1С встречается только в языке запросов, в конструкции ЕСТЬ NULL. К типам переменных во встроенном языке оно отношения не имеет.
Частые промахи при сравнении:
- ❌
ТипЗнч(Х) = "Число"— сравнение объектаТипсо строкой, условие всегда ложно, ошибки не будет. - ❌
ТипЗнч(Х) = Число— без кавычек иТип()платформа ищет переменнуюЧисло. - ❌ Проверка пустой ссылки через
Тип("Неопределено"). Пустая ссылка имеет тип своего справочника. Для неё нуженХ.Пустая()илиЗначениеЗаполнено(Х). - ✅
ТипЗнч(Х) = Тип("Неопределено")— правильно для реквизитов составного типа, в которые ещё ничего не выбрали.
Когда вариантов типов много, цепочка ИначеЕсли растёт. Её удобно заменить соответствием, где ключ — объект Тип:
Обработчики = Новый Соответствие;
Обработчики.Вставить(Тип("ДокументСсылка.ПоступлениеТоваровУслуг"), "ОбработатьПоступление");
Обработчики.Вставить(Тип("ДокументСсылка.РеализацияТоваровУслуг"), "ОбработатьРеализацию");
ИмяОбработчика = Обработчики.Получить(ТипЗнч(Документ));
Если ИмяОбработчика = Неопределено Тогда
ВызватьИсключение "Документ этого вида не поддерживается";
КонецЕсли;
Соответствие ищет ключ по равенству, а два объекта Тип для одного вида данных равны. Поэтому поиск работает.
Имя типа строкой: XMLТип, НайтиПоТипу и Строка()
Иногда тип нужен в виде текста: записать в журнал, сохранить в настройках, передать во внешнюю систему. Способов три, и результат у них разный.
| Способ | Что вернёт для ссылки на «Номенклатуру» | Когда применять |
|---|---|---|
XMLТип(Тип).ИмяТипа | CatalogRef.Номенклатура | Хранение, обмен, восстановление типа обратно |
Метаданные.НайтиПоТипу(Тип).ПолноеИмя() | Справочник.Номенклатура | Работа с метаданными, построение текста запроса |
Строка(Тип) | Представление для пользователя | Только вывод на экран |
XMLТип — для хранения и обмена
XMLТип(Тип) возвращает объект ТипДанныхXML с двумя свойствами: ИмяТипа и URIПространстваИмен. Для примитивов имя английское: decimal у числа, string у строки, boolean у булева, dateTime у даты. Для ссылок — CatalogRef.Имя, DocumentRef.Имя и так далее.
Есть и сокращённый вызов от значения: XMLТипЗнч(Значение). А обратную операцию выполняет ИзXMLТипа(): она по имени и пространству имён восстанавливает объект Тип.
ТипXML = XMLТипЗнч(Ссылка);
ИмяДляХранения = ТипXML.ИмяТипа; // "CatalogRef.Номенклатура"
ПространствоИмен = ТипXML.URIПространстваИмен;
// позже, при чтении
ВосстановленныйТип = ИзXMLТипа(ИмяДляХранения, ПространствоИмен);
Храните оба свойства вместе. Тогда тип восстановится однозначно.
НайтиПоТипу — для работы с метаданными
Метаданные.НайтиПоТипу(Тип) возвращает объект метаданных или Неопределено, если тип не относится к прикладным объектам (например, для числа). У найденного объекта есть Имя, Синоним и метод ПолноеИмя().
ОбъектМД = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));
Если ОбъектМД <> Неопределено Тогда
ТекстЗапроса = "ВЫБРАТЬ Т.Наименование ИЗ " + ОбъектМД.ПолноеИмя() + " КАК Т ГДЕ Т.Ссылка = &Ссылка";
КонецЕсли;
Так пишут универсальный код: один запрос для любого справочника, ссылку на который передали.
Объект Метаданные недоступен в модуле формы на клиенте. Такой код выносите в серверную процедуру или в общий серверный модуль.
Строка() — только для пользователя
Строка(Тип) даёт представление, которое видит пользователь. Оно зависит от языка интерфейса и может отличаться от имени объекта. Не сравнивайте типы через Строка(): код сломается при смене языка или синонима.
Составной тип и объект ОписаниеТипов
Реквизит составного типа может хранить значения разных типов. Например, реквизит «Получатель» в собственной обработке — ссылку на контрагента, на физлицо или на сотрудника. Перед обращением к полям значения тип надо проверить, иначе обращение к Получатель.ИНН упадёт на варианте, где такого реквизита нет.
Описание набора типов в 1С — объект ОписаниеТипов. Его возвращает свойство Тип у реквизита в метаданных, у колонки таблицы значений, у реквизита формы. Главные методы:
- 🔍
СодержитТип(Тип)— входит ли тип в описание, возвращаетИстинаилиЛожь. - 📋
Типы()— массив всех типов описания. - 🔄
ПривестиЗначение(Значение)— приводит значение к описанию (подробно ниже).
Создать описание можно перечислением имён через запятую:
Допустимые = Новый ОписаниеТипов("СправочникСсылка.Контрагенты, СправочникСсылка.ФизическиеЛица");
Если Допустимые.СодержитТип(ТипЗнч(Получатель)) Тогда
// значение одного из допустимых типов
КонецЕсли;
Проверить, какие типы разрешены у реквизита документа:
ОписаниеРеквизита = Метаданные.Документы.РеализацияТоваровУслуг.Реквизиты.Контрагент.Тип;
Для Каждого ТекТип Из ОписаниеРеквизита.Типы() Цикл
Сообщить(Метаданные.НайтиПоТипу(ТекТип).ПолноеИмя());
КонецЦикла;
Если в описании есть примитивный тип, НайтиПоТипу вернёт для него Неопределено, и вызов ПолноеИмя() даст ошибку. В таком цикле добавьте проверку на Неопределено.
Определяемые типы и характеристики
В конфигурациях на БСП составные типы часто задают не в самом реквизите, а через определяемый тип (ветка «Общие → Определяемые типы»). Код проверки от этого не меняется: у реквизита по-прежнему есть свойство Тип с объектом ОписаниеТипов, и СодержитТип() работает так же.
Другой источник составных типов — планы видов характеристик. У каждого вида характеристики есть реквизит ТипЗначения, тоже ОписаниеТипов. Перед записью значения характеристики удобно проверить его так:
Если Не ВидХарактеристики.ТипЗначения.СодержитТип(ТипЗнч(НовоеЗначение)) Тогда
ВызватьИсключение "Значение не подходит для этой характеристики";
КонецЕсли;
Так ошибка всплывёт сразу, с понятным текстом, а не при записи набора записей регистра.
Любая ссылка на справочник или документ
Частая задача — понять, ссылка ли это вообще и какого класса. У менеджеров коллекций есть метод ТипВсеСсылки(), он возвращает ОписаниеТипов со всеми ссылками этого класса:
Если Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
// ссылка на любой справочник
ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
// ссылка на любой документ
КонецЕсли;
В типовых конфигурациях на БСП для этого есть готовая функция ОбщегоНазначения.ЗначениеСсылочногоТипа(Значение). Она проверяет все ссылочные классы сразу, и свою проверку писать не нужно.
Приведение к типу и проверка совместимости
Узнать тип — половина задачи. Вторая половина — получить значение нужного типа из того, что пришло: из строки файла, из поля ввода, из реквизита составного типа.
| Способ | Что делает при неподходящем значении | Пример |
|---|---|---|
Число(Строка) | Вызывает исключение | Число("125") → 125 |
Строка(Значение) | Всегда даёт строку-представление | Строка(125) → “125” |
Дата(Строка) | Вызывает исключение, нужен формат ГГГГММДДччммсс | Дата("20261007") |
ОписаниеТипов.ПривестиЗначение() | Возвращает значение по умолчанию для типа | 0 для числа, пустую строку для строки |
На некорректной строке Число() падает с ошибкой Преобразование значения к типу Число не может быть выполнено. Для разбора файлов с мусором в данных удобнее ПривестиЗначение: строка из цифр станет числом, а нечисловая строка — нулём, без исключения.
ОписаниеЧисла = Новый ОписаниеТипов("Число");
Количество = ОписаниеЧисла.ПривестиЗначение(ЗначениеИзФайла);
// "15" → 15, "abc" → 0
Квалификаторы описания тоже работают при приведении. Например, строковый квалификатор длины обрежет текст:
Строка5 = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(5));
Код = Строка5.ПривестиЗначение("1234567"); // "12345"
ПривестиЗначение молча меняет данные. Ноль вместо «abc» удобен в отчёте, но опасен при загрузке цен. Там лучше проверить строку заранее и вывести пользователю номер строки файла с ошибкой.
Значение из реквизита составного типа к типу не приводят. Его проверяют через ТипЗнч и работают с ним как есть. Ссылка не превращается в другую ссылку: можно только получить из неё объект методом ПолучитьОбъект().
Типы в языке запросов
В запросах свои средства, и они часто быстрее, чем проверка в коде после выборки.
ТИПЗНАЧЕНИЯ(Поле) = ТИП(Документ.РеализацияТоваровУслуг)— сравнение типа поля.Поле ССЫЛКА Документ.РеализацияТоваровУслуг— та же проверка короче, удобна для регистратора.ВЫРАЗИТЬ(Поле КАК Документ.РеализацияТоваровУслуг)— приводит составное поле к одному типу.Поле ЕСТЬ NULL— проверка на NULL после левого соединения.
ВЫБРАТЬ
ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент КАК Контрагент
ИЗ
РегистрНакопления.ИмяРегистра КАК Движения
ГДЕ
Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
Зачем ВЫРАЗИТЬ: при обращении к полю составного регистратора без приведения платформа соединяет таблицы всех документов, которые могут быть регистраторами. С ВЫРАЗИТЬ соединение будет одно. На регистре с двадцатью видами регистраторов разница в скорости заметна.
Обратите внимание на тип в коде после выборки. Поле из левого соединения без пары вернёт NULL, и ТипЗнч(Выборка.Поле) = Тип("NULL"). Это не Неопределено и не пустая ссылка, проверять надо отдельно.
Отладка: как посмотреть тип в Конфигураторе
Когда условие с типом «не срабатывает», быстрее всего посмотреть фактический тип в отладчике.
- Поставьте точку останова на строке с условием:
F9или двойной щелчок по полю слева от кода. - Запустите отладку:
F5илиОтладка → Начать отладку. - Когда выполнение остановится, выделите переменную и нажмите
Shift+F9— откроется окно вычисления выражения. - Посмотрите колонку «Тип»: там видно, ссылка это, объект, структура данных формы или
NULL. - Для постоянного наблюдения добавьте выражение в
Отладка → Табло. Можно вписать прямоТипЗнч(Х)илиXMLТипЗнч(Х).ИмяТипа.
Если значение — ОписаниеТипов, раскройте его в окне вычисления или вычислите ОписаниеРеквизита.Типы(), чтобы увидеть массив типов.
Что чаще всего обнаруживается при такой проверке:
- 🧩 В модуле формы
Объект— этоДанныеФормыСтруктура, а неСправочникОбъект. Сравнение сТип("СправочникОбъект.Имя")ложно. Для настоящего объекта используютРеквизитФормыВЗначение("Объект")на сервере. - 🔗 Вместо ссылки пришёл объект или наоборот.
- 📄 Число пришло строкой из файла или из поля ввода:
"15"и15выглядят одинаково, а типы разные. - 🕳️ После запроса в поле
NULL, а код ждал пустую ссылку.
Без отладчика тип можно быстро вывести в сообщение: Сообщить(XMLТипЗнч(Х).ИмяТипа). В отличие от Строка(), имя будет точным и не зависит от синонимов.
Частые вопросы
Можно ли сохранить значение типа Тип в реквизит справочника?
Тип в реквизит не записывают. Храните имя из XMLТип и пространство имён в строковых реквизитах, а при чтении восстанавливайте тип через ИзXMLТипа.Работает ли ТипЗнч на клиенте?
ТипЗнч, Тип и ОписаниеТипов доступны и на клиенте, и на сервере. На тонком клиенте недоступен объект Метаданные, поэтому НайтиПоТипу вызывают на сервере.Как проверить, что значение — любой документ, не перечисляя все виды?
Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)). Описание включает ссылки на все документы конфигурации, и новые виды документов попадут в него автоматически.Чем ЗначениеЗаполнено отличается от проверки типа?
ЗначениеЗаполнено проверяет, не пустое ли значение: ноль, пустая строка, пустая ссылка, Неопределено и NULL дают Ложь. Тип она не определяет, поэтому для составных реквизитов нужны обе проверки.Почему два объекта Тип для одного справочника равны, а две ссылки на разные элементы — нет?
Тип описывает вид данных, а не конкретное значение. У всех элементов справочника «Номенклатура» тип один и тот же, а ссылки разные, потому что указывают на разные записи.