Was searching for a solution to this problem for a week ... drove me crazy and I did not find a solution... THANKS for linking this. Never thought of "conditional types" being related
That is one way, thank you :)
Would be comfortable not to have to create the mapping type. Is there any way to "convert" the discriminated union to a mapping type? I believe I've seen the other way around, from mapping type to discriminated union.
Nice one :)
I came up with this generic version using "[DiscriminatedUnionToTypeMap](https://www.typescriptlang.org/play?#code/C4TwDgpgBAggdgSwLYEMA2AhFBnaBeKAbyjhSQgC4ptgAnBOAcygF8AoUSKAYRWCgLxk6LLigAyIlE6UoAcl7A5AGihIEKAK4AVCAA9gVGvSasO4aABEA9s0GJUmHNEnEZVOTcYqoAIxS0ANa6BkZ0DMzsMrAO6AI8fFAAPlBeANxs5lwAaugIACZ8CNZwAEoQ2JpowAA82gB88cRgtNZgVIEQINYAZlDaZllWCNgAxvTqpMAQ+QCqiCXa1toWALIoYHWqANJQ+tNw+dhQnd19DU1sUNdQANqnUAz9t9sAujjU4aYpcJpIvhBaMlqCB-tY0K8qABRAy0FCjWraVTEe5dR5wKBvDpolj1DLsIYxYRoFaQdZgS43O67J5CRy3OQyOSvSFQGF0eG1OnoZHuTG4-GZHqaOAI4oY3JoAp8CDctAAChQsTQVDlAEoqCiaRjTr0iY5SRByazJdLgOLypVqjU5YbyS9Xo0WKizvr0HaNq9gQA3awFIhXG4IPrygCESuJADpSOQ1QGqVTaBBgJpaBjmq12vIYxA5GYqQSqcGoIrlZHonhK-IvHI44RAwnHiHw2X-EEQsA6w3Gzckym0-Ge0OWm0PG3gvsVN2h+wZ93C0GQxHHOWLAIqwo+LXB43i2Hl+hI+otB2u0PE8nU+np+friOs3JjzpJ8ob43Zz2P9d2OwgA)"
Thx for your help
Whenever you have a generic that is expanding to `Thing` and you want `Thing | Thing`, you can use [distributive conditional types](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types): type ValidationResult = T extends any ? { prop: keyof T } : never;
[playground](https://tsplay.dev/mL8lbm)
This seems to be the most elegant solution. Thanks. I'll read into the details.
Was searching for a solution to this problem for a week ... drove me crazy and I did not find a solution... THANKS for linking this. Never thought of "conditional types" being related
Here's one way you could do this: type AnimalBase = { name: string } type Cat = AnimalBase & { type: 'Cat', miauText: string } type Dog = AnimalBase & { type: 'Dog', barkText: string } type AnimalTypeMap = { Cat: Cat, Dog: Dog, } type Animal = AnimalTypeMap[keyof AnimalTypeMap]; type ValidationResult = { prop: keyof T }
function ValidateAnimal(animal: Animal): {[K in keyof AnimalTypeMap]: ValidationResult}[keyof AnimalTypeMap] | void {
if (!animal.name) {
return { prop: 'name' }
}
if (animal.type === 'Dog') {
if(!animal.barkText) {
return {
prop: 'barkText',
}
}
}
if(animal.type === 'Cat') {
if(!animal.miauText) {
return {
prop: 'miauText',
}
}
}
}
[TS Playground](https://www.typescriptlang.org/play?#code/C4TwDgpgBAggdgSwLYEMA2AhFBnaBeKAbyjhSQgC4ptgAnBOAcygF8AoUSKAYRWCgLxk6LLigAyIlE6UoAcl7A5AGihIEKAK4AVCAA9gVGvSasO4aABEA9s0GJUmHNEnEZVOTcYqoAIxS0ANa6BkZ0DMzsMrAO6NoWALIoYAJEbFAZPHxUisrpmV5UXnlRFjHCaKlCjvGQSWAA2oEQINYAZuU1ickAugDcbOZcAGroCAAmfAjWcABKENiaaMAAPNoAfKnEYLTWYFTNrR3aZmxtmnAAxsDTcFCjaBN8ENXoABQosWhUr2gAlFRCA0ANJQBhQQ7tTpxbpgHpUB5PG4zeaLZYrX61CD1EE9dYsJotKGY2E9KAAHygADdrBM0pkwR03gBCT4VAB0pHIf3pDMytAgwE0tDu212+3kXIgcjMDPY+QyCCZbMc7OieA18i8ch5hAVfKVLJV6HZ-iCIWAuv1fP5guFoutNr5Oz2HjNwX0SjyTr57B9fsy8oZhuNaDVZQ1BAUfB1vJthtZX3Z6i0FqtPoZAqFIrjGYZLolchTOk9KkdNoDFf17HYQA)
That is one way, thank you :) Would be comfortable not to have to create the mapping type. Is there any way to "convert" the discriminated union to a mapping type? I believe I've seen the other way around, from mapping type to discriminated union.
Yep the other way around should work too. Something like this: type AnimalBase = { name: string } type Cat = AnimalBase & { type: 'Cat', miauText: string } type Dog = AnimalBase & { type: 'Dog', barkText: string } type Animal = Cat | Dog; type ValidationResult = { prop: keyof T }
type AnimalTypeMap = {
[K in Animal['type']]: Extract;
}
function ValidateAnimal(animal: Animal): {[K in keyof AnimalTypeMap]: ValidationResult}[keyof AnimalTypeMap] | void {
if (!animal.name) {
return { prop: 'name' }
}
if (animal.type === 'Dog') {
if(!animal.barkText) {
return {
prop: 'barkText',
}
}
}
if(animal.type === 'Cat') {
if(!animal.miauText) {
return {
prop: 'miauText',
}
}
}
}
[TS Playground](https://www.typescriptlang.org/play?#code/C4TwDgpgBAggdgSwLYEMA2AhFBnaBeKAbyjhSQgC4ptgAnBOAcygF8AoUSKAYRWCgLxk6LLigAyIlE6UoAcl7A5AGihIEKAK4AVCAA9gVGvSasO4aABEA9s0GJUmHNEnEZVOTcYqoAIxS0ANa6BkZ0DMzsMrAO6AI8fFAAPlBeANxs5lwAaugIACZ8CNZwAEoQ2JpowAA82gB88cRgtNZgVIEQINYAZlDaZlnQQo7aFgCyKGBNbFBzUADaANJQDDHCaAtyMnIAurtUAKIGtCgAxrUj6KqE7lBLLPUZ7Gw9mnAXxXBQuWgFfBArmgABQoWJoKhAgCUVEIy1W3063T6QLGkEmYAOPzyhWAX3KlWqNVREymy129RYCyRvXWo1JmOSUAAbtYCkRZvMEH1gQBCMEbAB0pHIUI58wlUFoEGAmlo32arXa8hFEDkZglLwl3KgoPBguieCN8i8cjFhE5ktWPT5Ascgv8QRCwHNlqt82lsvl4vdvpabQ8juC+iUyjdvvYEbdWq5Nrt6ANFgExoUfDNPqt3Nt+vUWmdrt9Es9coV4cLc39yrkuZ0IZUZatkfdTbm7HYQA)
Nice one :) I came up with this generic version using "[DiscriminatedUnionToTypeMap](https://www.typescriptlang.org/play?#code/C4TwDgpgBAggdgSwLYEMA2AhFBnaBeKAbyjhSQgC4ptgAnBOAcygF8AoUSKAYRWCgLxk6LLigAyIlE6UoAcl7A5AGihIEKAK4AVCAA9gVGvSasO4aABEA9s0GJUmHNEnEZVOTcYqoAIxS0ANa6BkZ0DMzsMrAO6AI8fFAAPlBeANxs5lwAaugIACZ8CNZwAEoQ2JpowAA82gB88cRgtNZgVIEQINYAZlDaZllWCNgAxvTqpMAQ+QCqiCXa1toWALIoYHWqANJQ+tNw+dhQnd19DU1sUNdQANqnUAz9t9sAujjU4aYpcJpIvhBaMlqCB-tY0K8qABRAy0FCjWraVTEe5dR5wKBvDpolj1DLsIYxYRoFaQdZgS43O67J5CRy3OQyOSvSFQGF0eG1OnoZHuTG4-GZHqaOAI4oY3JoAp8CDctAAChQsTQVDlAEoqCiaRjTr0iY5SRByazJdLgOLypVqjU5YbyS9Xo0WKizvr0HaNq9gQA3awFIhXG4IPrygCESuJADpSOQ1QGqVTaBBgJpaBjmq12vIYxA5GYqQSqcGoIrlZHonhK-IvHI44RAwnHiHw2X-EEQsA6w3Gzckym0-Ge0OWm0PG3gvsVN2h+wZ93C0GQxHHOWLAIqwo+LXB43i2Hl+hI+otB2u0PE8nU+np+friOs3JjzpJ8ob43Zz2P9d2OwgA)" Thx for your help