diff --git a/README.md b/README.md index 48f0bf5..b249f9f 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ Checkout the full [API reference](https://ts-roids.ashgw.me/) for all usage exam #### Types +- [`PartializedUnion`](https://ts-roids.ashgw.me/types/PartializedUnion.html) - Creates a union type where each variant has its specific properties required, while other properties are optional. + - [`Prune`](https://ts-roids.ashgw.me/types/Prune.html) - Prune a type `T` by recursively omitting properties of type `N` (defaults to [`NotIncluded`](https://ts-roids.ashgw.me/types/NotIncluded.html)). - [`DeepToPrimitive`](https://ts-roids.ashgw.me/types/DeepToPrimitive.html) - Recursively transforms an object type T into a type where all properties are replaced with their corresponding primitive types. - [`Assign`](https://ts-roids.ashgw.me/types/Assign.html) - Copies all enumerable own properties from one target object to a source array of objects. @@ -72,6 +74,8 @@ Checkout the full [API reference](https://ts-roids.ashgw.me/) for all usage exam - [`ExcludeNull`](https://ts-roids.ashgw.me/types/ExcludeNull.html) - Excludes ``null`` from a type ``T``. - [`ExcludeNullable`](https://ts-roids.ashgw.me/types/ExcludeNullable.html) - Excludes [`Nullable`](https://ts-roids.ashgw.me/types/Nullable.html) from a type ``T``. - [`ExcludeUndefined`](https://ts-roids.ashgw.me/types/ExcludeUndefined.html) - Excludes `undefined` from a type ``T``. +- [`KeysOfUnion`](https://ts-roids.ashgw.me/types/KeysOfUnion.html) - Extracts the union of keys from a given union of object types, useful for accessing all possible keys in unions. +- [`Simplify`](https://ts-roids.ashgw.me/types/Simplify.html) - Flattens the structure of a type by resolving intersections and simplifying nested mapped types, enhancing readability. - [`Extends`](https://ts-roids.ashgw.me/types/Extends.html) - Evaluates whether one type ``T`` is assignable to another type ``U``. - [`Falsy`](https://ts-roids.ashgw.me/types/Falsy.html) - Represents a type that is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) JavaScript. - [`FalsyProperties`](https://ts-roids.ashgw.me/types/FalsyProperties.html) - Extracts falsy properties from an object type ``T``. diff --git a/src/types.ts b/src/types.ts index b26af6d..1ccf782 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2272,3 +2272,75 @@ export type Prune = OmitExactlyByTypeDeep; export type PartialExcept = { [P in K]: T[P]; } & Partial>; + +/** + * `KeysOfUnion` extracts the union of keys from a given union of object types. + * This is useful in scenarios where you need to access all possible keys across + * unioned object types within conditional or mapped types. + * + * @template T - The union of object types to extract keys from. + * + * @example + * ```ts + * type UnionKeys = KeysOfUnion<{ a: string } | { b: number }>; // Result: 'a' | 'b' + * ``` + */ + +type KeysOfUnion = T extends T ? keyof T : never; +/** + * `Simplify` flattens the structure of a given type by resolving intersections + * and reducing redundant wrapping, making complex types easier to work with. + * This type is particularly helpful for deeply nested mapped types, where + * readability and simplicity of the resulting type is crucial. + * + * @template T - The type to simplify. + * + * @example + * ```ts + * type Flattened = Simplify<{ a: string } & { b: number }>; // Result: { a: string; b: number } + * ``` + */ +export type Simplify = { [KeyType in Keys]: T[KeyType] } & EmptyObject; + +/** + * `PartializedUnion` creates a union type where each member has its own properties as required, + * while properties from other members of the union are made optional and set to `undefined`. + * This is useful for cases where different configurations or variants in a union require only their specific fields. + * + * @template T - The union of object types for which partially optionalized variants should be created. + * @template AllKeys - The union of all possible keys across the union's types, derived from `KeysOfUnion`. + * + * @example + * ```ts + * type Config = PartializedUnion< + * | { dbConnectionString: string; maxConnections: number } + * | { apiEndpoint: string; apiKey: string } + * | { storageBucket: string; accessKeyId: string; secretAccessKey: string } + * >; + * + * // Example usage: + * function configureService(config: Config) { + * if (config.dbConnectionString) { + * console.log(`Configuring database with connection string ${config.dbConnectionString}`); + * } else if (config.apiEndpoint) { + * console.log(`Configuring API with endpoint ${config.apiEndpoint}`); + * } else if (config.storageBucket && config.accessKeyId && config.secretAccessKey) { + * console.log(`Configuring storage bucket ${config.storageBucket}`); + * } else { + * console.log('Invalid configuration'); + * } + * } + * + * configureService({ dbConnectionString: 'postgres://...', maxConnections: 100 }); + * configureService({ apiEndpoint: 'https://api.example.com', apiKey: '1234' }); + * configureService({ storageBucket: 'my-bucket', accessKeyId: 'AKIA...', secretAccessKey: 'abcd' }); + * ``` + */ +export type PartializedUnion< + T extends object, + AllKeys extends KeysOfUnion = KeysOfUnion, +> = Simplify< + T extends unknown + ? T & Partial>, undefined>> + : never +>;