mirror of
https://github.com/sindresorhus/type-fest.git
synced 2025-12-08 19:25:05 +00:00
89 lines
2.2 KiB
TypeScript
89 lines
2.2 KiB
TypeScript
import type {NonRecursiveType, ReadonlyKeysOfUnion, ValueOfUnion} from './internal';
|
|
import type {KeysOfUnion} from './keys-of-union';
|
|
import type {SharedUnionFields} from './shared-union-fields';
|
|
import type {Simplify} from './simplify';
|
|
import type {UnknownArray} from './unknown-array';
|
|
|
|
/**
|
|
Create a type with all fields from a union of object types.
|
|
|
|
Use-cases:
|
|
- You want a safe object type where each key exists in the union object.
|
|
|
|
@example
|
|
```
|
|
import type {AllUnionFields} from 'type-fest';
|
|
|
|
type Cat = {
|
|
name: string;
|
|
type: 'cat';
|
|
catType: string;
|
|
};
|
|
|
|
type Dog = {
|
|
name: string;
|
|
type: 'dog';
|
|
dogType: string;
|
|
};
|
|
|
|
function displayPetInfo(petInfo: Cat | Dog) {
|
|
// typeof petInfo =>
|
|
// {
|
|
// name: string;
|
|
// type: 'cat';
|
|
// catType: string;
|
|
// } | {
|
|
// name: string;
|
|
// type: 'dog';
|
|
// dogType: string;
|
|
// }
|
|
|
|
console.log('name: ', petInfo.name);
|
|
console.log('type: ', petInfo.type);
|
|
|
|
// TypeScript complains about `catType` and `dogType` not existing on type `Cat | Dog`.
|
|
console.log('animal type: ', petInfo.catType ?? petInfo.dogType);
|
|
}
|
|
|
|
function displayPetInfo(petInfo: AllUnionFields<Cat | Dog>) {
|
|
// typeof petInfo =>
|
|
// {
|
|
// name: string;
|
|
// type: 'cat' | 'dog';
|
|
// catType?: string;
|
|
// dogType?: string;
|
|
// }
|
|
|
|
console.log('name: ', petInfo.name);
|
|
console.log('type: ', petInfo.type);
|
|
|
|
// No TypeScript error.
|
|
console.log('animal type: ', petInfo.catType ?? petInfo.dogType);
|
|
}
|
|
```
|
|
|
|
@see SharedUnionFields
|
|
|
|
@category Object
|
|
@category Union
|
|
*/
|
|
export type AllUnionFields<Union> =
|
|
Extract<Union, NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown> | UnknownArray> extends infer SkippedMembers
|
|
? Exclude<Union, SkippedMembers> extends infer RelevantMembers
|
|
?
|
|
| SkippedMembers
|
|
| Simplify<
|
|
// Include fields that are common in all union members
|
|
SharedUnionFields<RelevantMembers> &
|
|
// Include readonly fields present in any union member
|
|
{
|
|
readonly [P in ReadonlyKeysOfUnion<RelevantMembers>]?: ValueOfUnion<RelevantMembers, P & KeysOfUnion<RelevantMembers>>
|
|
} &
|
|
// Include remaining fields that are neither common nor readonly
|
|
{
|
|
[P in Exclude<KeysOfUnion<RelevantMembers>, ReadonlyKeysOfUnion<RelevantMembers> | keyof RelevantMembers>]?: ValueOfUnion<RelevantMembers, P>
|
|
}
|
|
>
|
|
: never
|
|
: never;
|