typia icon indicating copy to clipboard operation
typia copied to clipboard

Typia runtime validation fails on intersections of discriminated union types

Open Anders-eide-stacc opened this issue 8 months ago • 2 comments

Bug Report

📝 Summary

Write a short summary of the bug in here.

  • Typia Version: 9.3.1-dev.20250520
  • Expected behavior: Ability to validate union types containing complex types
  • Actual behavior: Fails with false positive errors

I am trying to validate an instance of PartyWithRole in the following type hierarchy:

type PartyWithRole = Party & PartyRoleInfo;
type Party = Individual | Corporation;

interface Individual {
  type: "individual";
  birthDate: Date;
}

interface Corporation {
  type: "corporation";
}

type PartyRoleInfo = { partyRole: "customer" } | {
  partyRole: "other"
  otherPartyRole: string
}

But I run into issues where typia seems unable to validate the partyRole property. I am not sure what the actual problem stems from, but it seems to only occur if I have a non-primitive property in the heirarchy (in this case, I kept the birthDate property).

Note: I have trimmed away most of the properties in my actual type hierarchy here to try and create the smallest example possible that still exhibits the issue.

⏯ Playground Link

Here is a link that demonstrates the issue:

https://typia.io/playground/?script=JYWwDg9gTgLgBDAnmYBDOAzKERwERIqp4DcAUGQMYQB2AzvMDQCbABuwzArqgDZwBeOAG8ycfIQCmeAFz4mrDtz54ANGPwAjYLAAWAEVQxpcmpIDucQ8YAUASnXi8YVLEQAlCLxP4IMXZJQahp4fgFQAAquSJ7eshJ+fLyIcGx8nHAMUEwA5sEAvhRScFFugnAAkizsnDz8AD5wAMLQkFBGwLTkxaVIAOrA-rGS5b0pAGQl0R5eklUYEORkTMZQGKiUI1WKtXwiGlJyeAo1yrykGtp61pJyNyRwAPSPcADVALTvcADKkpIgdAQEDgmhG-hG2D8cEoqC4dBGEAwCACcGAdDoXEkqhBXHgzAgkjoNAA5PANjA6skENkcjlAnAwNhNN5cOZBroILi4FwaJ0aAhkCNhvMIGRCssaKt1ptmq1oB1aPtxId8NQoG0FTQLuKetNhTQFuVhAy9bMjpQ4TAcIE8HB8nBGqJxC43MMjmEbRoPZFTd45FlcmKKNR6PA0rxOJr3ISuLx4EJCGgAHThyPGAA8YwGQ1mAD4bCclHU7OQQ3RZkneBAcjZU8wozG4yWgA

💻 Code reproducing the bug

import typia from "typia";
const individual: PartyWithRole = {
  "type": "individual",
  "birthDate": new Date(),
  "partyRole": "other",
  "otherPartyRole": "some-valid-string",
}

type PartyWithRole = Party & PartyRoleInfo;
type Party = Individual | Corporation;

interface Individual {
  type: "individual";
  birthDate: Date;
}

interface Corporation {
  type: "corporation";
}

type PartyRoleInfo = { partyRole: "customer" } | {
  partyRole: "other"
  otherPartyRole: string
}


const validationResult = typia.validate<PartyWithRole>(individual);
if (!validationResult.success) {
  throw validationResult;
}

Example result from above code:

{
  success: false,
  errors: [
    {
      path: '$input.partyRole',
      expected: '"customer"',
      value: 'other'
    }
  ],
  data: {
    type: 'individual',
    birthDate: 2025-06-10T10:43:59.087Z,
    partyRole: 'other',
    otherPartyRole: 'some-valid-string'
  }
}

Anders-eide-stacc avatar Jun 10 '25 10:06 Anders-eide-stacc

Oh yeah, for now, I am simply validating one section of my intersections as a workaround:

const validationResult = typia.validate<Party>(individual).success && typia.validate<PartyRoleInfo>(individual).success

Which seems to work fine so far, but obviously isn't great, since I won't be able to check for extraneous properties 😅

Anders-eide-stacc avatar Jun 10 '25 10:06 Anders-eide-stacc

Just watned to plus one this. I have some code where I have to manually construct a validator for each side of the union otherwise typia fails.

bradleat avatar Jun 27 '25 15:06 bradleat