question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Validating a union type in a modular way

See original GitHub issue

I have a discriminated union like this:

type UnionCaseA = {
  type: 'UnionCaseA'
  propertyX: string
}

type UnionCaseB = {
  type: 'UnionCaseB'
  propertyY: number
}

I have validation for UnionCaseA:

const validateUnionCaseA = (): ValidationChain[] => {
  return [
    body('propertyX').notEmpty().withMessage('is required').isString().trim()
  ]
}

I have a test for it:

describe('validateUnionCaseA', (): void => {
  it('should validate "propertyX"', async () => {
    const req = createRequest({
      headers: {
        'accept-language': 'de-DE'
      },
      body: {
        type: 'UnionCaseA'
      }
    })
    await testExpressValidatorMiddleware(
      req,
      createResponse(),
      validateUnionCaseA()
    )

    const result = validationResult(req)
    result
      .array()
      .filter((i) => i.msg === 'is required')
      .length.should.equal(1)
  })
})

This test succeeds.

Next, I have a validation for the Union Type itself:

const validateUnion = (): ValidationChain[] => {
  return [
    body('type').custom(async (value: string, { req }) => {
      const result = await check('type')
        .isIn(['UnionCaseA', 'UnionCaseB'])
        .withMessage('Must be "UnionCaseA" or "UnionCaseB"')
        .run(req)

      const isValid = result.isEmpty()
      if (!isValid) return [result]

      switch (value) {
        case 'UnionCaseA':
          return validateUnionCaseA()
        case 'UnionCaseB':
          return validateUnionCaseB()
      }
    })
  ]
}

There’s a succeeding test as well:

describe('validateUnion', (): void => {
  it('should validate "type"', async () => {
    const req = createRequest({
      body: {
        type: ''
      }
    })
    await testExpressValidatorMiddleware(req, createResponse(), validateUnion())

    const result = validationResult(req)
    result
      .array()
      .filter((i) => i.msg === 'Must be "UnionCaseA" or "UnionCaseB"')
      .length.should.equal(1)
  })
})

However, when I’m trying to test the union including its cases in a modular manner (the switch statement inside validateUnion), this test fails

it('should validate "UnionCaseA"', async () => {
    const req = createRequest({
      body: {
        type: 'UnionCaseA'
      }
    })
    await testExpressValidatorMiddleware(req, createResponse(), validateUnion())

    const result = validationResult(req)
    result
      .array()
      .filter((i) => i.msg === 'is required')
      .length.should.equal(1)
  })

result.array() is empty.

Looks like I’m doing something wrong but after a day of debugging I’m still not getting it.

I’ve created a repro here: https://github.com/AlexZeitler/express-validator-nested-repro

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
AlexZeitlercommented, Aug 24, 2021

Thanks, this has been a copy/paste issue.

0reactions
fedecicommented, Aug 23, 2021

The first part of validateUnion (up to the switch) still does not make sense to me 😃 You don’t need to run the first check .isIn()... imperatively. Also consider checking out oneOf middleware that does what you are trying to do in this issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

class-validator validate union type
I have a mongoose discriminator schema, which mean the data will be different according to one of the attributes. class Feature { name:...
Read more >
Designing with types: Single case union types
The simplest way to create a separate type is to wrap the underlying string type inside another type. We can do it using...
Read more >
[Feature Request] Provide a discriminated union type ...
My interest in using descriminators is not related to openAPI or JSONSchema, I want a way of using Unions, where: Avoid having to...
Read more >
Handbook - Unions and Intersection Types
A union type describes a value that can be one of several types. We use the vertical bar ( | ) to separate...
Read more >
Getting the Best of TypeScript and GraphQL: Union Types
I hope this blog post helped you to better understand TypeScript unions and GraphQL unions and the way to use them in your...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found