Ответ 1
Я думаю, у меня есть решение для вас. Вы ищете что-то, что принимает тип T
и производит связанный тип, который содержит хотя бы одно свойство из T
. То есть он похож на Partial<T>
, но исключает пустой объект.
Если это так, вот оно:
type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U]
Рассекать: прежде всего, AtLeastOne<T>
пересекается с чем-то Partial<T>
. U[keyof U]
означает, что это объединение всех значений свойств U
. И я определил (значение по умолчанию) U
как сопоставленный тип, где каждое свойство T
сопоставлено с Pick<T, K>
, типом с одним свойством для ключа K
, (Например, Pick<{foo: string, bar: number},'foo'>
эквивалентно {foo: string}
... он "выбирает" свойство 'foo'
из исходного типа.) Это означает, что U[keyof U]
в этом случае является объединением всех возможных типов с одним свойством из T
.
Хм, это может сбить с толку. Давайте посмотрим шаг за шагом, как он работает со следующим конкретным типом:
type FullLinkRestSource = {
model: string;
rel: string;
title: string;
}
type LinkRestSource = AtLeastOne<FullLinkRestSource>
Это расширяется до
type LinkRestSource = AtLeastOne<FullLinkRestSource, {
[K in keyof FullLinkRestSource]: Pick<FullLinkRestSource, K>
}>
или
type LinkRestSource = AtLeastOne<FullLinkRestSource, {
model: Pick<FullLinkRestSource, 'model'>,
rel: Pick<FullLinkRestSource, 'rel'>,
title: Pick<FullLinkRestSource, 'title'>
}>
или
type LinkRestSource = AtLeastOne<FullLinkRestSource, {
model: {model: string},
rel: {rel: string},
title: {title: string}>
}>
или
type LinkRestSource = Partial<FullLinkRestSource> & {
model: {model: string},
rel: {rel: string},
title: {title: string}>
}[keyof {
model: {model: string},
rel: {rel: string},
title: {title: string}>
}]
или
type LinkRestSource = Partial<FullLinkRestSource> & {
model: {model: string},
rel: {rel: string},
title: {title: string}>
}['model' | 'rel' | 'title']
или
type LinkRestSource = Partial<FullLinkRestSource> &
({model: string} | {rel: string} | {title: string})
или
type LinkRestSource = {model?: string, rel?: string, title?: string} &
({model: string} | {rel: string} | {title: string})
или
type LinkRestSource = { model: string, rel?: string, title?: string }
| {model?: string, rel: string, title?: string}
| {model?: string, rel?: string, title: string}
что, я думаю, то, что вы хотите.
Вы можете проверить это:
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 = {} // missing property
const error1: LinkRestSource = { model: 'a', titel: 'c' } // excess property on string literal
Итак, это работает для вас? Удачи!