Skip to content

Instantly share code, notes, and snippets.

@JonathanLoscalzo
Last active May 21, 2025 04:09
Show Gist options
  • Save JonathanLoscalzo/c6b4e804230b3231e1a9dc8fb32c1d9c to your computer and use it in GitHub Desktop.
Save JonathanLoscalzo/c6b4e804230b3231e1a9dc8fb32c1d9c to your computer and use it in GitHub Desktop.
Validation issues using special mapped-types
import {
IntersectionType,
OmitType,
PartialType,
PickType,
} from '@nestjs/mapped-types';
import { IsNotEmpty, IsString, Length, validate } from 'class-validator';
export class Base {
@IsString()
@Length(2, 100)
subject?: string;
}
export class Create extends Base {
@IsNotEmpty()
subject: string;
}
describe('Create', () => {
let create: Create;
beforeEach(() => {
create = new Create();
});
// PASS
describe('Validations from Create', () => {
it('should pass if subject is filled', async () => {
create.subject = 'asdf';
const results = await validate(create);
expect(results.length).toBe(0);
});
it('should fail if subject is not filled', async () => {
const results = await validate(create);
expect(results.length).toBe(1);
});
});
// FAILS. Not detecting Base Validations.
describe('Validations from Base', () => {
it('it should fail when subject len is less than 2', async () => {
create.subject = 'a';
const results = await validate(create);
expect(results.length).toBe(1);
});
it('it should fail when subject is not a string', async () => {
create.subject = 1 as unknown as string;
const results = await validate(create);
expect(results.length).toBe(1);
});
});
});
export class UpdatePartialType extends PartialType(Create) {}
describe('UpdatePartialType', () => {
let update: UpdatePartialType;
beforeEach(() => {
update = new UpdatePartialType();
});
// PASS
describe('Validations from Create', () => {
it('should pass if subject is complete', async () => {
update.subject = 'asdf';
const results = await validate(update);
expect(results.length).toBe(0); // FAIL. Not detecting Length.
});
it('it should pass if subject is empty', async () => {
const results = await validate(update);
expect(results.length).toBe(0);
});
});
// FAILS. Not detecting Base Validations.
describe('Validations from Base', () => {
it('it should fail when subject len is less than 2', async () => {
update.subject = 'a';
const results = await validate(update);
expect(results.length).toBe(1);
});
it('it should fail when subject is not a string', async () => {
update.subject = 1 as unknown as string;
const results = await validate(update);
expect(results.length).toBe(1);
});
});
});
export class UpdatePartialWithPickType extends IntersectionType(
PartialType(Create),
PickType(Create, ['subject']),
) {}
describe('UpdatePartialWithPickType', () => {
let update: UpdatePartialWithPickType;
beforeEach(() => {
update = new UpdatePartialWithPickType();
});
describe('Validations from Create', () => {
// PASS
it('should pass if subject is filled', async () => {
update.subject = 'asdf';
const results = await validate(update);
expect(results.length).toBe(0); // FAIL. Not detecting Length.
});
// FAILS. Not detecting IsNotEmpty when PickType is used.
it('it should fail if subject is empty', async () => {
const results = await validate(update);
expect(results.length).toBe(1);
});
});
// FAILS. Not detecting Base Validations.
describe('Validations from Base', () => {
it('it should fail when subject len is less than 2', async () => {
update.subject = 'a';
const results = await validate(update);
expect(results.length).toBe(1);
});
it('it should fail when subject is not a string', async () => {
update.subject = 1 as unknown as string;
const results = await validate(update);
expect(results.length).toBe(1);
});
});
});
export class UpdatePartialWithOmitType extends IntersectionType(
OmitType(PartialType(Create), ['subject']),
PickType(Create, ['subject']),
) {}
describe('UpdatePartial3', () => {
let update: UpdatePartialWithOmitType;
beforeEach(() => {
update = new UpdatePartialWithOmitType();
});
// PASS
describe('Validations from Create', () => {
it('should pass if subject is filled', async () => {
update.subject = 'asdf';
const results = await validate(update);
expect(results.length).toBe(0);
});
// PASS. Better than UpdatePartialWithPickType.
it('it should fail if subject is empty', async () => {
const results = await validate(update);
expect(results.length).toBe(1);
});
});
// FAILS. Not detecting Base Validations.
describe('Validations from Base', () => {
it('it should fail when subject len is less than 2', async () => {
update.subject = 'a';
const results = await validate(update);
expect(results.length).toBe(1);
});
it('it should fail when subject is not a string', async () => {
update.subject = 1 as unknown as string;
const results = await validate(update);
expect(results.length).toBe(1);
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment