Проверка типа данных во встроенном языке 1С:Предприятия 8.3
Содержание
Тип значения переменной в 1С определяют функцией ТипЗнч(). Её результат сравнивают с Тип("ИмяТипа"): Если ТипЗнч(Значение) = Тип("Число") Тогда. Для ссылок имя типа пишут с суффиксом «Ссылка»: Тип("СправочникСсылка.Номенклатура"), Тип("ДокументСсылка.РеализацияТоваровУслуг").
Всё остальное — частные случаи этого приёма. Как проверить сразу несколько типов, как определить тип в запросе, как отличить Неопределено от Null и пустой ссылки, что делать с ячейками табличного документа и вложенными структурами — разобрано ниже. Примеры относятся к платформе 8.3 и подходят для любой типовой конфигурации: это возможности встроенного языка, а не конкретного прикладного решения.
Функция ТипЗнч: как узнать тип значения переменной
ТипЗнч(Значение) возвращает объект типа Тип. Это не строка, а отдельное значение, которое можно сравнивать, хранить в переменной и передавать в функции.
Количество = 12.5;
Если ТипЗнч(Количество) = Тип("Число") Тогда
Сообщить("Это число");
КонецЕсли;
Контрагент = Справочники.Контрагенты.НайтиПоКоду("000000001");
Если ТипЗнч(Контрагент) = Тип("СправочникСсылка.Контрагенты") Тогда
Сообщить("Это ссылка на элемент справочника «Контрагенты»");
КонецЕсли;
Как пишется имя типа
| Что проверяем | Выражение |
|---|---|
| Число, строка, дата, булево | Тип("Число"), Тип("Строка"), Тип("Дата"), Тип("Булево") |
| Пустые значения | Тип("Неопределено"), Тип("Null") |
| Ссылка справочника | Тип("СправочникСсылка.Номенклатура") |
| Ссылка документа | Тип("ДокументСсылка.ПоступлениеТоваровУслуг") |
| Значение перечисления | Тип("ПеречислениеСсылка.ВидыДоговоров") |
| Объект справочника (не ссылка) | Тип("СправочникОбъект.Номенклатура") |
| Универсальные коллекции | Тип("Массив"), Тип("Структура"), Тип("Соответствие"), Тип("ТаблицаЗначений") |
| Идентификатор | Тип("УникальныйИдентификатор") |
Тип("Справочник.Номенклатура") без слова «Ссылка» вызовет ошибку Тип не определен. Платформа ищет тип по точному имени, а такого типа нет.
Как посмотреть тип в отладчике
Если непонятно, что лежит в переменной, поставьте точку останова и откройте окно вычисления выражения (Shift+F9). Введите имя переменной — в колонке «Тип» будет показан фактический тип значения. Для реквизитов составного типа это самый быстрый способ понять, что пришло из базы.
Почему не стоит сравнивать строки
Частый соблазн — написать Строка(ТипЗнч(Значение)) = "Число". Для примитивов это иногда срабатывает, но строковое представление типа зависит от языка интерфейса и синонима объекта в конфигураторе. Переименовали синоним справочника — проверка тихо перестала работать.
Если нужно стабильное текстовое имя типа (например, для лога или обмена), используйте XMLТипЗнч:
ИмяТипа = XMLТипЗнч(Контрагент).ИмяТипа; // "CatalogRef.Контрагенты"
Оно не зависит от синонимов и языка, поэтому подходит для сохранения в файлы и регистры.
Проверка принадлежности к группе типов
Сравнение через = хорошо, когда тип один. Когда допустимых типов несколько или нужно ответить на вопрос «это вообще ссылка на справочник?», удобнее другие инструменты.
ОписаниеТипов и метод СодержитТип
ОписаниеТипов хранит набор типов. Его метод СодержитТип() отвечает, входит ли тип в набор:
ДопустимыеТипы = Новый ОписаниеТипов("Число, Строка");
Если ДопустимыеТипы.СодержитТип(ТипЗнч(Значение)) Тогда
// значение — число или строка
КонецЕсли;
Так же проверяют, подходит ли значение для реквизита составного типа. У каждого реквизита в метаданных есть свойство Тип с готовым описанием типов:
ТипРеквизита = Метаданные.Документы.РеализацияТоваровУслуг.Реквизиты.Контрагент.Тип;
Если Не ТипРеквизита.СодержитТип(ТипЗнч(НовоеЗначение)) Тогда
ВызватьИсключение "Значение не подходит для реквизита «Контрагент»";
КонецЕсли;
Список всех типов из описания возвращает метод Типы() — массив значений Тип.
Любая ссылка справочника или документа
Чтобы не перечислять все справочники вручную, используйте менеджеры коллекций:
Если Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
// ссылка на элемент любого справочника
ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
// ссылка на любой документ
КонецЕсли;
В конфигурациях на Библиотеке стандартных подсистем есть готовая функция ОбщегоНазначения.ЭтоСсылка(Тип). Она отвечает, является ли переданный тип ссылочным, и избавляет от длинных цепочек условий.
Через метаданные: что это за объект
Когда нужно не только понять «ссылка или нет», но и узнать, на какой объект она указывает, используйте Метаданные.НайтиПоТипу:
ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Значение));
Если ОбъектМетаданных <> Неопределено Тогда
Сообщить(ОбъектМетаданных.ПолноеИмя()); // "Справочник.Контрагенты"
КонецЕсли;
Для ссылки есть короткий путь — Значение.Метаданные(). Но он упадёт с ошибкой, если в переменной не ссылка, поэтому сначала проверьте тип.
Объект Метаданные недоступен на тонком клиенте. Проверку через метаданные выполняйте на сервере, а на клиенте ограничьтесь ТипЗнч и ОписаниеТипов.
Проверка типа в запросе
В языке запросов свои конструкции. Имя типа в них пишется без «Ссылка»:
ВЫБРАТЬ
Движения.Регистратор,
ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.ПоступлениеТоваровУслуг).Номер КАК НомерПоступления
ИЗ
РегистрНакопления.ТоварыНаСкладах КАК Движения
ГДЕ
Движения.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
Варианты условия:
- 🔹
Поле ССЫЛКА Документ.ПоступлениеТоваровУслуг— короткая проверка ссылочного поля; - 🔹
ТИПЗНАЧЕНИЯ(Поле) = ТИП(Документ.ПоступлениеТоваровУслуг)— то же через сравнение типов, работает и с примитивами:ТИП(ЧИСЛО); - 🔹
ВЫРАЗИТЬ(Поле КАК Документ.ПоступлениеТоваровУслуг)— приведение составного поля к одному типу, чтобы обратиться к его реквизитам без лишних соединений со всеми возможными таблицами.
Фильтровать по типу лучше в запросе, а не перебором результата в цикле: в выборку не попадут лишние строки.
Неопределено, Null и пустая ссылка: три разных «ничего»
Эти значения выглядят одинаково пустыми, но ведут себя по-разному. Перепутать их — верный путь к ошибке Значение не является значением объектного типа.
| Значение | Откуда берётся | Как проверить |
|---|---|---|
Неопределено | Переменная без значения, необязательный параметр, реквизит составного типа без значения, ключ не найден в соответствии | Значение = Неопределено |
Null | Поле запроса из левого соединения, где пары не нашлось | Значение = Null или ТипЗнч(Значение) = Тип("Null") |
| Пустая ссылка | Незаполненный реквизит ссылочного типа | Значение.Пустая() или Значение = Справочники.Контрагенты.ПустаяСсылка() |
Универсальная проверка заполненности
Если неважно, какое именно «ничего» пришло, используйте ЗначениеЗаполнено(). Функция возвращает Ложь для Неопределено, Null, пустой ссылки, нуля, пустой строки и пустой даты:
Если Не ЗначениеЗаполнено(Объект.Контрагент) Тогда
ВызватьИсключение "Не заполнен контрагент";
КонецЕсли;
Но если ноль — допустимое значение (например, количество в возвратной строке), ЗначениеЗаполнено его отбракует. Тогда проверяйте тип явно: ТипЗнч(Значение) = Тип("Число").
Безопасный порядок проверок перед обращением к реквизиту
Метод Пустая() есть только у ссылок. Вызов на Неопределено даст исключение, поэтому порядок проверок важен:
Если ТипЗнч(Значение) = Тип("СправочникСсылка.Контрагенты")
И Не Значение.Пустая() Тогда
ИНН = Значение.ИНН;
КонецЕсли;
Условия во встроенном языке вычисляются слева направо, и при ложной первой части вторая не выполняется. Поэтому проверка типа идёт первой.
Null — убирать в запросе
Null удобнее не ловить в коде, а заменить прямо в запросе:
ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
Тогда в коде будет число, и арифметика не сломается на Null.
Типы в табличном документе и таблице значений
Табличные данные — частый источник путаницы с типами. Особенно при загрузке из Excel.
Ячейки табличного документа
Когда файл Excel читают в ТабличныйДокумент, содержимое ячеек обычно доступно через свойство Текст — это всегда строка. Число «1 250,50» придёт как текст с пробелом и запятой, и сравнение с числом даст Ложь.
Строку перед сравнением нужно привести к числу. Надёжный вариант с обработкой мусора:
Функция ЧислоИзТекста(Знач Текст)
Текст = СокрЛП(Текст);
Текст = СтрЗаменить(Текст, " ", "");
Текст = СтрЗаменить(Текст, Символы.НПП, "");
Текст = СтрЗаменить(Текст, ",", ".");
Если Текст = "" Тогда
Возврат Неопределено;
КонецЕсли;
Попытка
Возврат Число(Текст);
Исключение
Возврат Неопределено;
КонецПопытки;
КонецФункции
Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл
ТекстСуммы = ТабДок.Область(НомерСтроки, 3, НомерСтроки, 3).Текст;
Сумма = ЧислоИзТекста(ТекстСуммы);
Если Сумма = Неопределено Тогда
Сообщить("Строка " + Формат(НомерСтроки, "ЧГ=0") + ": в колонке суммы не число");
Продолжить;
КонецЕсли;
// дальше работаем с числом
КонецЦикла;
Функция возвращает Неопределено вместо исключения. Вызывающий код сам решает, пропустить строку или прервать загрузку.
У области ячеек есть и типизированный режим: свойства СодержитЗначение, ТипЗначения (описание типов) и Значение. Его используют, когда ячейка заполняется программно и должна хранить ссылку или число, а не текст.
Колонки таблицы значений
Колонка ТаблицаЗначений может иметь тип, а может не иметь. Тип задают при добавлении:
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
Таблица.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));
Таблица.Колонки.Добавить("Комментарий"); // без типа
Разница на практике:
- ✅ в типизированную колонку значение приводится к её типу при записи: строка «abc» в колонке «Сумма» станет нулём;
- ⚠️ в колонку без типа ложится что угодно, и в соседних строках могут оказаться число и строка;
- ⚠️ если таблицу передают в запрос параметром и помещают во временную таблицу, колонки должны быть типизированы, иначе запрос завершится ошибкой.
Тип колонки читается через Таблица.Колонки.Сумма.ТипЗначения. Это тоже ОписаниеТипов, к нему применимы СодержитТип() и Типы().
Тот же механизм приведения доступен отдельно — метод ПривестиЗначение() у описания типов. Он возвращает значение нужного типа или значение по умолчанию этого типа, если преобразовать не удалось.
Сложные значения: структура, соответствие, массив
Значения внутри Структура, Соответствие и Массив могут быть любого типа, в том числе вложенными коллекциями. Так обычно выглядит результат разбора JSON или ответ HTTP-сервиса.
Безопасное чтение ключей
У структуры обращение к несуществующему ключу через точку вызовет ошибку. Проверяйте ключ методом Свойство():
Если Параметры.Свойство("Организация", Организация)
И ТипЗнч(Организация) = Тип("СправочникСсылка.Организации") Тогда
// ключ есть, и в нём ссылка нужного типа
КонецЕсли;
У соответствия Получить() возвращает Неопределено, если ключа нет. Но Неопределено может лежать и как настоящее значение. Если различие «ключа нет» и «ключ есть, но пустой» важно, не кладите в соответствие Неопределено как значение — храните пустоту явно, например пустой строкой или нулём.
JSON: структура или соответствие
ПрочитатьJSON(Чтение) по умолчанию создаёт Структура. Если вторым параметром передать Истина, объекты JSON станут Соответствие. Это важно: ключи вида "1-й" или "order id" нельзя сделать ключом структуры, и чтение без второго параметра завершится ошибкой.
Рекурсивный обход с выводом типов
Когда структура данных неизвестна, помогает функция, которая обходит её целиком и печатает тип каждого элемента:
Функция ДеревоТипов(Значение, Отступ = "") Экспорт
Результат = "";
ТекущийТип = ТипЗнч(Значение);
Если ТекущийТип = Тип("Структура") Или ТекущийТип = Тип("ФиксированнаяСтруктура")
Или ТекущийТип = Тип("Соответствие") Или ТекущийТип = Тип("ФиксированноеСоответствие") Тогда
Для Каждого КлючИЗначение Из Значение Цикл
Результат = Результат + Отступ + Строка(КлючИЗначение.Ключ) + ": "
+ XMLТипЗнч(КлючИЗначение.Значение).ИмяТипа + Символы.ПС;
Результат = Результат + ДеревоТипов(КлючИЗначение.Значение, Отступ + " ");
КонецЦикла;
ИначеЕсли ТекущийТип = Тип("Массив") Или ТекущийТип = Тип("ФиксированныйМассив") Тогда
Для Индекс = 0 По Значение.ВГраница() Цикл
Элемент = Значение[Индекс];
Результат = Результат + Отступ + "[" + Формат(Индекс, "ЧН=0; ЧГ=0") + "]: "
+ XMLТипЗнч(Элемент).ИмяТипа + Символы.ПС;
Результат = Результат + ДеревоТипов(Элемент, Отступ + " ");
КонецЦикла;
КонецЕсли;
Возврат Результат;
КонецФункции
Для {"id": 15, "items": [{"name": "Бумага"}]} функция вернёт примерно такое дерево: id: decimal, items: Array, [0]: Structure, name: string. Пустой массив ВГраница() вернёт -1, и цикл просто не выполнится.
Переменную под тип назовите ТекущийТип, а не Тип. Имя Тип совпадает с глобальной функцией, и такой код хуже читается.
Частые ошибки при проверке типов и как их избежать
- ❌ Сравнение типа со строкой.
ТипЗнч(Х) = "Число"всегда даётЛожь: слеваТип, справаСтрока. Ошибки нет, просто условие никогда не срабатывает. - ❌ Обращение к реквизиту без проверки.
Значение.НаименованиеприНеопределенопадает сЗначение не является значением объектного типа (Наименование). Сначала тип, потом реквизит. - ❌ Путаница ссылки и объекта. После
Ссылка.ПолучитьОбъект()тип ужеСправочникОбъект.…, и проверка наСправочникСсылка.…не пройдёт. - ❌
Тип("…")внутри большого цикла. На тысячах итераций каждый вызов разбирает строку имени. Вычислите тип один раз до цикла:ТипНоменклатура = Тип("СправочникСсылка.Номенклатура"). - ❌ Проверка через
Метаданныена клиенте. В тонком клиенте объект недоступен — выносите проверку в серверную процедуру. - ❌ Тип по строковому представлению. Работает до первого переименования синонима или запуска на другом языке интерфейса.
Когда тип лучше задать, а не проверять
Многие проверки исчезают, если типы описаны заранее: у реквизитов формы, параметров процедур в комментарии, колонок таблиц значений. Чем уже тип на входе, тем меньше ветвлений в коде.
Для составных реквизитов полезно отдельное правило: перед записью проверяйте значение через Тип реквизита в метаданных и СодержитТип(). Ошибка сразу покажет, кто передал неподходящее значение, а не всплывёт позже в отчёте.
Вопросы о типах данных в 1С
Можно ли получить тип значения на клиенте?
ТипЗнч, Тип и ОписаниеТипов работают и на клиенте, и на сервере. На клиенте недоступен только объект Метаданные.Как определить тип реквизита, а не его текущего значения?
Метаданные.Справочники.Номенклатура.Реквизиты.Артикул.Тип. Это описание типов; список типов вернёт метод Типы().Чем ТипЗнч отличается от XMLТипЗнч?
ТипЗнч возвращает объект Тип для сравнения в коде. XMLТипЗнч возвращает имя типа для XML-сериализации, например CatalogRef.Номенклатура, — его удобно писать в логи и файлы обмена.Как проверить, что значение — элемент перечисления?
ТипЗнч(Х) = Тип("ПеречислениеСсылка.ВидыДоговоров"). Для любого перечисления подходит Перечисления.ТипВсеСсылки().СодержитТип(ТипЗнч(Х)).Почему проверка типа ссылки работает в одной базе и не работает в другой?
Тип("СправочникСсылка.…") вызовет ошибку Тип не определен.