Skip to content

Commit

Permalink
RequireAtLeastOne: Make other given keys optional (#142)
Browse files Browse the repository at this point in the history
  • Loading branch information
ulken committed Nov 16, 2020
1 parent 00e04c7 commit 6110607
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 13 deletions.
21 changes: 11 additions & 10 deletions source/require-at-least-one.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ const responder: RequireAtLeastOne<Responder, 'text' | 'json'> = {
};
```
*/
export type RequireAtLeastOne<ObjectType, KeysType extends keyof ObjectType = keyof ObjectType> =
{
// For each Key in KeysType make a mapped type
[Key in KeysType]: (
// …by picking that Key's type and making it required
Required<Pick<ObjectType, Key>>
)
}[KeysType]
// …then, make intersection types by adding the remaining keys to each mapped type.
& Except<ObjectType, KeysType>;
export type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType
> = {
// For each `Key` in `KeysType` make a mapped type:
[Key in KeysType]-?: Required<Pick<ObjectType, Key>> & // 1. Make `Key`'s type required
// 2. Make all other keys in `KeysType` optional
Partial<Pick<ObjectType, Exclude<KeysType, Key>>>;
}[KeysType] &
// 3. Add the remaining keys not in `KeysType`
Except<ObjectType, KeysType>;
21 changes: 18 additions & 3 deletions test-d/require-at-least-one.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ type SystemMessages = {
optional?: string;
};

type ValidMessages = RequireAtLeastOne<SystemMessages, 'macos' | 'linux' | 'windows'>;
type MessageBoard<M> = (messages: M) => string;

type ValidMessages = RequireAtLeastOne<
SystemMessages,
'macos' | 'linux' | 'windows'
>;
const test = (_: ValidMessages): void => {}; // eslint-disable-line @typescript-eslint/no-empty-function

test({macos: 'hey', default: 'hello'});
Expand All @@ -22,5 +27,15 @@ expectError(test({}));
expectError(test({macos: 'hey'}));
expectError(test({default: 'hello'}));

declare const atLeastOneWithoutKeys: RequireAtLeastOne<{a: number; b: number}>;
expectAssignable<{a: number; b?: number} | {a?: number; b: number}>(atLeastOneWithoutKeys);
declare const atLeastOneWithoutKeys: RequireAtLeastOne<{
a: number;
b: number;
}>;
expectAssignable<{a: number; b?: number} | {a?: number; b: number}>(
atLeastOneWithoutKeys
);

expectAssignable<MessageBoard<ValidMessages>>(
({macos = '', linux = '🐧', windows = '⊞'}) =>
`${linux} + ${windows} = ${macos}`
);

0 comments on commit 6110607

Please sign in to comment.