@IsCreditCard

Декоратор @IsCreditCard в class-validator применяется для проверки строкового значения на соответствие формату банковской кредитной карты. Валидация выполняется не только по структуре номера, но и с учётом алгоритма Луна, что позволяет отсеивать случайные или заведомо некорректные значения.

@IsCreditCard используется в DTO-объектах, моделях валидации и слоях входных данных, где требуется гарантировать корректность платежных реквизитов. Основная задача декоратора — обеспечить соответствие значения одному из стандартных форматов карт, используемых международными платёжными системами.

Ключевые характеристики проверки:

  • соответствие числовому формату;
  • проверка длины номера (обычно 13–19 цифр);
  • валидация по алгоритму Луна;
  • игнорирование пробелов и дефисов при нормализации входа.

Синтаксис использования

Базовое применение:

import { IsCreditCard } from 'class-validator';

export class PaymentDto {
  @IsCreditCard()
  cardNumber: string;
}

В этом случае применяется стандартная валидация без дополнительных ограничений.

Поведение валидации

Проверка включает несколько этапов:

Нормализация строки

Перед анализом входное значение приводится к единому виду:

  • удаляются пробелы;
  • удаляются дефисы;
  • строка приводится к последовательности цифр.

Пример допустимых входных данных:

  • 4111 1111 1111 1111
  • 4111-1111-1111-1111
  • 4111111111111111

Все три варианта интерпретируются одинаково.

Проверка формата

После нормализации выполняется проверка:

  • строка должна содержать только цифры;
  • длина должна соответствовать диапазону допустимых значений;
  • не допускаются буквенные символы и спецсимволы.

Алгоритм Луна

Финальный этап — вычисление контрольной суммы:

  • цифры номера обрабатываются справа налево;
  • каждая вторая цифра удваивается;
  • если результат больше 9, вычитается 9;
  • итоговая сумма должна делиться на 10 без остатка.

Если проверка не проходит, значение считается недействительным независимо от формального соответствия длине и структуре.

Поддерживаемые форматы

Декоратор ориентирован на общую валидацию и не привязан к конкретному типу платёжной системы, но фактически поддерживает распространённые стандарты:

  • Visa (13–19 цифр, начинается с 4)
  • MasterCard (16 цифр, диапазон BIN 51–55 и 2221–2720)
  • American Express (15 цифр, начинается с 34 или 37)
  • Discover и другие международные схемы

При этом проверка не определяет тип карты, а лишь валидирует корректность номера.

Поведение при пустых значениях

По умолчанию:

  • undefined и null пропускаются другими декораторами (@IsOptional() влияет на поведение);
  • пустая строка считается ошибкой валидации;
  • пробелы без цифр не проходят проверку.

Пример комбинирования:

import { IsOptional, IsCreditCard } from 'class-validator';

export class PaymentDto {
  @IsOptional()
  @IsCreditCard()
  cardNumber?: string;
}

Пользовательские сообщения об ошибках

Можно переопределить стандартное сообщение:

import { IsCreditCard } from 'class-validator';

export class PaymentDto {
  @IsCreditCard({}, { message: 'Номер карты указан некорректно' })
  cardNumber: string;
}

Сообщение будет возвращено в массиве ошибок валидации при несоответствии.

Работа в NestJS и ValidationPipe

В связке с NestJS декоратор используется внутри DTO, а проверка выполняется через ValidationPipe:

import { IsCreditCard } from 'class-validator';

export class CreatePaymentDto {
  @IsCreditCard()
  cardNumber: string;
}
app.useGlobalPipes(
  new ValidationPipe({
    whitelist: true,
    transform: true,
  }),
);

При поступлении запроса:

  1. тело запроса преобразуется в DTO;
  2. выполняется проверка всех декораторов;
  3. при ошибке возвращается HTTP 400 с описанием нарушений.

Взаимодействие с преобразованием данных

При использовании class-transformer важно учитывать порядок обработки:

  • сначала выполняется трансформация типов;
  • затем — валидация class-validator.

Если поле приводится к числу, декоратор @IsCreditCard может начать работать некорректно, поскольку ожидает строку. Поэтому для номеров карт числовой тип не применяется.

Пример корректного подхода:

import { Transform } from 'class-transformer';
import { IsCreditCard } from 'class-validator';

export class PaymentDto {
  @Transform(({ value }) => value?.replace(/\s|-/g, ''))
  @IsCreditCard()
  cardNumber: string;
}

Валидация массивов

Декоратор применяется к каждому элементу массива через @ValidateNested или комбинацию с @IsArray:

import { IsArray, IsCreditCard } from 'class-validator';

export class BulkPaymentDto {
  @IsArray()
  @IsCreditCard({ each: true })
  cards: string[];
}

Флаг each: true активирует проверку каждого элемента отдельно.

Частые ошибки при использовании

Передача числового значения

cardNumber: 4111111111111111

Проблема: число теряет точность в JavaScript и становится некорректным для проверки. Кроме того, декоратор ожидает строку.

Наличие посторонних символов

  • пробелы внутри строки без нормализации;
  • символы +, _, .;
  • буквы латиницы или кириллицы.

Преждевременная трансформация

Если значение очищается или изменяется до валидации без контроля, можно случайно исказить структуру номера.

Кастомная логика поверх стандартной проверки

Иногда требуется расширить проверку:

  • ограничение по BIN-диапазону;
  • запрет определённых платёжных систем;
  • региональные ограничения.

В таких случаях @IsCreditCard используется как базовый фильтр, а дополнительные условия реализуются через @Validate или кастомные валидаторы:

import { Validate } from 'class-validator';

export class PaymentDto {
  @IsCreditCard()
  @Validate(CustomCardValidator)
  cardNumber: string;
}

Производительность и особенности реализации

Проверка алгоритма Луна имеет сложность O(n), где n — количество цифр в номере. При типичных длинах карт (16–19 цифр) влияние на производительность минимально, даже при массовой валидации массивов данных.

Основная нагрузка возникает не на вычислении, а на:

  • создании объектов ошибок;
  • работе рефлексии метаданных;
  • обработке nested-структур.

Ограничения декоратора

  • не определяет банк-эмитент;
  • не проверяет активность карты;
  • не гарантирует существование счёта;
  • не валидирует CVV/CVC;
  • не выполняет сетевую проверку платёжных систем.

Фактически проверяется только математическая и структурная корректность номера.

Использование в доменной модели

В слоях доменной логики декоратор часто применяется на границе системы:

  • вход API;
  • формы регистрации оплаты;
  • импорт платёжных данных.

Внутри бизнес-логики данные обычно уже считаются валидными, а @IsCreditCard выполняет роль фильтра первичной очистки входного потока.