0

I currently have a typeorm class an I am looking to have specific functionality where I can "tag" properties with this Or generic. Below in my example I am using an interface but the idea should be the same.

I would like to do something like this:

export type Or<T, B> = T & { or?: undefined };

interface Example { 
  name: Or<string, 'firstName' | 'lastName'>
  firstName: Or<string, 'name'>
  lastName: Or<string, 'name'>
}

And I'd like to pass Example into another generic Build<Example> for it to be something like this:

type UnionKeys<T> = T extends T? keyof T : never;
type StrictUnionHelper<T, TAll> = T extends T? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, undefined>> : never;
export type StrictUnion<T> = StrictUnionHelper<T, T>

type E = StrictUnion<
  { firstName: string, lastName: string } |
  { name: string }
>

Is something like this possible?

Update:

This is sort of in the right direction:

type Build<T> = StrictUnion<{ [P in keyof T]: T[P] extends { or: any } ? Pick<T, T[P]['or']> : never }[keyof T]>

const v:Build<Example> = { 
  name: 'hi'
}
ThomasReggi
  • 55,053
  • 85
  • 237
  • 424
  • What is StrictUnion? I found [another SO topic](https://stackoverflow.com/questions/52677576/typescript-discriminated-union-allows-invalid-state) but it's not implemented in TypeScript – Vahid Jan 19 '20 at 19:09
  • Added with StrictUnion,. – ThomasReggi Jan 19 '20 at 19:10

1 Answers1

0
export type Or<T, B> = T & { or?: B };

interface Example { 
  name: Or<string, 'firstName' | 'lastName'>
  firstName: Or<string, 'name'>
  lastName: Or<string, 'name'>
}

type Build<T> = StrictUnion<{ [P in keyof T]: T[P] extends { or?: any } ? Pick<T, T[P]['or']> : never }[keyof T]>

type Working = Build<Example>

const a: Working = { 
  firstName: 'meow',
  lastName: 'woof'
}

const b: Working = { 
  name: 'meow'
}
ThomasReggi
  • 55,053
  • 85
  • 237
  • 424