Ответ 1
ОБНОВЛЕНИЕ 2018-06-22:
Этот ответ был написан год назад, до того, как удивительная функция условных типов была выпущена в TypeScript 2.8. Так что этот ответ больше не нужен. Пожалуйста, смотрите новый ответ @krzysztof-kaczor ниже, чтобы узнать, как получить это поведение в TypeScript 2.8 и выше.
Хорошо, вот моя лучшая попытка сумасшедшего, но полностью общего решения (требующего TypeScript 2.4 и выше), которое может вам не стоить, но если вы хотите его использовать, будьте моим гостем:
Во-первых, нам нужна логическая логика на уровне типов:
type False = '0'
type True = '1'
type Bool = False | True
type IfElse<Cond extends Bool, Then, Else> = {'0': Else; '1': Then;}[Cond];
Все, что вам нужно знать, это то, что тип IfElse<True,A,B>
оценивается как A
а IfElse<False,A,B>
оценивается как B
Теперь мы определяем тип записи Rec<K,V,X>
, объект с ключом K
и типом значения V
, где Rec<K,V,True>
означает, что свойство является обязательным, а Rec<K,V,False>
означает свойство необязательно:
type Rec<K extends string, V, Required extends Bool> = IfElse<Required, Record<K, V>, Partial<Record<K, V>>>
На данный момент мы можем перейти к вашим типам User
и DeepPartialUser
. Давайте опишем общую UserSchema<R>
где каждое свойство, которое нас интересует, является обязательным или необязательным, в зависимости от того, является ли R
True
или False
:
type UserSchema<R extends Bool> =
Rec<'emailAddress', string, R> &
Rec<'verification', (
Rec<'verified', boolean, R> &
Rec<'verificationCode', string, R>
), R> &
Rec<'activeApps', string[], R>
Гадкий, правда? Но мы можем наконец описать как User
и DeepPartialUser
как:
interface User extends UserSchema<True> { } // required
interface DeepPartialUser extends UserSchema<False> { } // optional
И увидеть это в действии:
var user: User = {
emailAddress: '[email protected]',
verification: {
verified: true,
verificationCode: 'shazam'
},
activeApps: ['netflix','facebook','angrybirds']
} // any missing properties or extra will cause an error
var deepPartialUser: DeepPartialUser = {
emailAddress: '[email protected]',
verification: {
verified: false
}
} // missing properties are fine, extra will still error
Вот и ты. Надеюсь, это поможет!