From 71cb283402577635149758b8474fa9e6f134ecb4 Mon Sep 17 00:00:00 2001 From: Ulad Kasach Date: Sat, 25 May 2024 12:17:38 -0400 Subject: [PATCH] feat(types): add PickAny type, symmetric with PickOne --- src/index.ts | 1 + src/types/PickAny.test.ts | 48 +++++++++++++++++++++++++++++++++++++++ src/types/PickAny.ts | 14 ++++++++++++ src/types/PickOne.test.ts | 19 +++++++++++----- 4 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 src/types/PickAny.test.ts create mode 100644 src/types/PickAny.ts diff --git a/src/index.ts b/src/index.ts index b24516d..c70212b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,3 +15,4 @@ export * from './companions/pick'; export * from './types/Literalize'; export * from './wrappers/withAssure'; export * from './checks/isKeyOf'; +export * from './types/PickAny'; diff --git a/src/types/PickAny.test.ts b/src/types/PickAny.test.ts new file mode 100644 index 0000000..4a664a6 --- /dev/null +++ b/src/types/PickAny.test.ts @@ -0,0 +1,48 @@ +import { PickAny } from './PickAny'; + +describe('PickAny', () => { + it('should constrain type correctly', async () => { + const findFlowers = async ( + input: PickAny<{ + color: { + petals: string; + }; + size: { + choice: 'LARGE' | 'SMALL'; + }; + }>, + ) => { + // ... + }; + + // you can find by color + await findFlowers({ + color: { + petals: 'white', + }, + }); + + // you can find by size + await findFlowers({ + size: { + choice: 'LARGE', + }, + }); + + // you can find by both + await findFlowers({ + color: { + petals: 'white', + }, + size: { + choice: 'LARGE', + }, + }); + + // you can't find by neither + await findFlowers({ + // @ts-expect-error - cant be neither + size: {}, + }); + }); +}); diff --git a/src/types/PickAny.ts b/src/types/PickAny.ts new file mode 100644 index 0000000..325624a --- /dev/null +++ b/src/types/PickAny.ts @@ -0,0 +1,14 @@ +/** + * creates a type which requires specifying at least one, or more, key of an object + * + * ref: + * - https://stackoverflow.com/a/49725198/3068233 + */ +export type PickAny = Pick< + TObj, + Exclude +> & + { + [K in TKeys]-?: Required> & + Partial>>; + }[TKeys]; diff --git a/src/types/PickOne.test.ts b/src/types/PickOne.test.ts index 9effa92..a966fe0 100644 --- a/src/types/PickOne.test.ts +++ b/src/types/PickOne.test.ts @@ -36,11 +36,18 @@ describe('PickOne', () => { }); // you can't find by both - // await findWrench({ - // size: { - // metric: { millimeters: 16 }, - // imperial: { inches: '5/16' }, - // }, - // }); + await findWrench({ + // @ts-expect-error - cant be both + size: { + metric: { millimeters: 16 }, + imperial: { inches: '5/16' }, + }, + }); + + // you can't find by neither + await findWrench({ + // @ts-expect-error - cant be neither + size: {}, + }); }); });