Проверка типа переменной во встроенном языке 1С:Предприятия 8.3

· 9 мин

Содержание

Тип значения в 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"). Это не Неопределено и не пустая ссылка, проверять надо отдельно.

Отладка: как посмотреть тип в Конфигураторе

Когда условие с типом «не срабатывает», быстрее всего посмотреть фактический тип в отладчике.

  1. Поставьте точку останова на строке с условием: F9 или двойной щелчок по полю слева от кода.
  2. Запустите отладку: F5 или Отладка → Начать отладку.
  3. Когда выполнение остановится, выделите переменную и нажмите Shift+F9 — откроется окно вычисления выражения.
  4. Посмотрите колонку «Тип»: там видно, ссылка это, объект, структура данных формы или NULL.
  5. Для постоянного наблюдения добавьте выражение в Отладка → Табло. Можно вписать прямо ТипЗнч(Х) или XMLТипЗнч(Х).ИмяТипа.

Если значение — ОписаниеТипов, раскройте его в окне вычисления или вычислите ОписаниеРеквизита.Типы(), чтобы увидеть массив типов.

Что чаще всего обнаруживается при такой проверке:

  • 🧩 В модуле формы Объект — это ДанныеФормыСтруктура, а не СправочникОбъект. Сравнение с Тип("СправочникОбъект.Имя") ложно. Для настоящего объекта используют РеквизитФормыВЗначение("Объект") на сервере.
  • 🔗 Вместо ссылки пришёл объект или наоборот.
  • 📄 Число пришло строкой из файла или из поля ввода: "15" и 15 выглядят одинаково, а типы разные.
  • 🕳️ После запроса в поле NULL, а код ждал пустую ссылку.

Без отладчика тип можно быстро вывести в сообщение: Сообщить(XMLТипЗнч(Х).ИмяТипа). В отличие от Строка(), имя будет точным и не зависит от синонимов.

Проверьте себя
Что вернёт выражение ТипЗнч(Х) = "Число", если в Х лежит 10?
Какой тип у пустой ссылки на справочник?
Какой способ подходит, чтобы сохранить тип в настройках и потом восстановить?

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

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