I think I have a solution for you. You are looking for something that takes a type T and produces a related type that contains at least one property from T That is, it is similar to Partial<T> , but excludes an empty object.
If so, here it is:
type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U]
Dissect: First of all, AtLeastOne<T> intersects with something Partial<T> . U[keyof U] means that it is the union of all property values ββof U And I defined (default) U as a mapped type , where each T property is mapped to Pick<T, K> , a type with one property for the K key, (For example, Pick<{foo: string, bar: number},'foo'> equivalent to {foo: string} ... it "selects" the 'foo' property from the original type.) This means that U[keyof U] in this case is the union of all possible types with one property from T
Hmm, this can be confusing. Let's see step by step how it works with the following specific type:
type FullLinkRestSource = { model: string; rel: string; title: string; } type LinkRestSource = AtLeastOne<FullLinkRestSource>
It expands to
type LinkRestSource = AtLeastOne<FullLinkRestSource, { [K in keyof FullLinkRestSource]: Pick<FullLinkRestSource, K> }>
or
type LinkRestSource = AtLeastOne<FullLinkRestSource, { model: Pick<FullLinkRestSource, 'model'>, rel: Pick<FullLinkRestSource, 'rel'>, title: Pick<FullLinkRestSource, 'title'> }>
or
type LinkRestSource = AtLeastOne<FullLinkRestSource, { model: {model: string}, rel: {rel: string}, title: {title: string}> }>
or
type LinkRestSource = Partial<FullLinkRestSource> & { model: {model: string}, rel: {rel: string}, title: {title: string}> }[keyof { model: {model: string}, rel: {rel: string}, title: {title: string}> }]
or
type LinkRestSource = Partial<FullLinkRestSource> & { model: {model: string}, rel: {rel: string}, title: {title: string}> }['model' | 'rel' | 'title']
or
type LinkRestSource = Partial<FullLinkRestSource> & ({model: string} | {rel: string} | {title: string})
or
type LinkRestSource = {model?: string, rel?: string, title?: string} & ({model: string} | {rel: string} | {title: string})
or
type LinkRestSource = { model: string, rel?: string, title?: string } | {model?: string, rel: string, title?: string} | {model?: string, rel?: string, title: string}
which, I think, is what you want.
You can check this out:
const okay0: LinkRestSource = { model: 'a', rel: 'b', title: 'c' } const okay1: LinkRestSource = { model: 'a', rel: 'b' } const okay2: LinkRestSource = { model: 'a' } const okay3: LinkRestSource = { rel: 'b' } const okay4: LinkRestSource = { title: 'c' } const error0: LinkRestSource = {}
So, does this work for you? Good luck