| 
 | 1 | +import type { UnwrapTagged, TagContainer } from './tagged.js';  | 
 | 2 | +import type { IsLiteral } from './is-literal.js';  | 
 | 3 | +import type { Primitive } from './primitive.js';  | 
 | 4 | +import type { Not } from './internal/type.js';  | 
 | 5 | +import type { IsEqual } from './is-equal.js';  | 
 | 6 | +import type { ValueOf } from './value-of.js';  | 
 | 7 | + | 
 | 8 | +/**  | 
 | 9 | +Creates a union of the literal members from a given union type, removing wide primitive or infinite types.  | 
 | 10 | +
  | 
 | 11 | +This utility helps you extract only the literal members from a "literal union" type  | 
 | 12 | +(e.g., `'foo' | 'bar' | string` becomes `'foo' | 'bar'`), saving you from defining separate types for literals and unions.  | 
 | 13 | +
  | 
 | 14 | +It works with all primitive and tagged types, and supports two strictness modes:  | 
 | 15 | +
  | 
 | 16 | +- **Strict mode (`Strict = true`)**: Removes any infinite signature type (e.g., `abc${string}`, `123${number}`).  | 
 | 17 | +- **Non-strict mode (`Strict = false`)**: Removes only wide primitive types (e.g., `string`, `number`).  | 
 | 18 | +
  | 
 | 19 | +@default true  | 
 | 20 | +
  | 
 | 21 | +@example  | 
 | 22 | +```ts  | 
 | 23 | +import type { LiteralOf } from 'type-fest';  | 
 | 24 | +
  | 
 | 25 | +// String example:  | 
 | 26 | +type Pet = LiteralUnion<'dog' | 'cat' | `${string}Dog`, string>;  | 
 | 27 | +//    ^? type Pet = 'dog' | 'cat' | `${string}Dog` | (string & {})  | 
 | 28 | +type PetLiteralStrict = LiteralOf<Pet>;  | 
 | 29 | +//    ^? type PetLiteralNonStrict = 'dog' | 'cat'   | 
 | 30 | +type PetLiteralNonStrict = LiteralOf<Pet, false>;  | 
 | 31 | +//    ^? type PetLiteralStrict = 'dog' | 'cat' | `${string}Dog`  | 
 | 32 | +
  | 
 | 33 | +// Number example:  | 
 | 34 | +type Nums = LiteralUnion<0 | 1 | 2, number>;  | 
 | 35 | +//    ^? type Nums = 0 | 1 | 2 | (number & {})  | 
 | 36 | +type NumsLiteral = LiteralOf<Nums>;  | 
 | 37 | +//    ^? type NumsLiteral = 0 | 1 | 2  | 
 | 38 | +
  | 
 | 39 | +// Symbol example:  | 
 | 40 | +declare const sym1: unique symbol;  | 
 | 41 | +declare const sym2: unique symbol;  | 
 | 42 | +type Symbols = LiteralUnion<typeof sym1 | typeof sym2, symbol>;  | 
 | 43 | +//    ^? type Symbols = typeof sym1 | typeof sym2 | (symbol & {})  | 
 | 44 | +type SymbolsLiteral = LiteralOf<Symbols>;  | 
 | 45 | +//    ^? type SymbolsLiteral = typeof sym1 | typeof sym2  | 
 | 46 | +
  | 
 | 47 | +// BigInt example:  | 
 | 48 | +type Big = LiteralUnion<1n | 2n, bigint>;  | 
 | 49 | +//    ^? type Big = 1n | 2n | (bigint & {})  | 
 | 50 | +type BigLiteral = LiteralOf<Big>;  | 
 | 51 | +//    ^? type BigLiteral = 1n | 2n  | 
 | 52 | +
  | 
 | 53 | +```  | 
 | 54 | +
  | 
 | 55 | +@author benzaria  | 
 | 56 | +@see LiteralUnion  | 
 | 57 | +@category Type  | 
 | 58 | +*/  | 
 | 59 | +export type LiteralOf<  | 
 | 60 | +    LiteralUnion extends Primitive,  | 
 | 61 | +    Strict extends boolean = true,  | 
 | 62 | +> = ValueOf<{  | 
 | 63 | +    [P in Primitive as string]: LiteralUnion extends P  | 
 | 64 | +    ? _LiteralOf<LiteralUnion, P, Strict>  | 
 | 65 | +    : never  | 
 | 66 | +}>;  | 
 | 67 | + | 
 | 68 | +type _LiteralOf<U, P, S> = ValueOf<{  | 
 | 69 | +    [K in U as string]: (  | 
 | 70 | +        S extends true  | 
 | 71 | +        ? Not<IsLiteral<  | 
 | 72 | +            K extends TagContainer<{ [J in PropertyKey]: any }>  | 
 | 73 | +            ? UnwrapTagged<K>  | 
 | 74 | +            : K  | 
 | 75 | +        >>  | 
 | 76 | +        : IsEqual<K, (P & Record<never, never>)>  | 
 | 77 | +    ) extends true  | 
 | 78 | +    ? never  | 
 | 79 | +    : K  | 
 | 80 | +}>;  | 
 | 81 | + | 
 | 82 | +/**  | 
 | 83 | +
  | 
 | 84 | +? Explanation:  | 
 | 85 | +
  | 
 | 86 | +- LiteralOf iterates over all primitive types (string, number, symbol, bigint, boolean).  | 
 | 87 | +- For each, if the input type extends that primitive, applies _LiteralOf.  | 
 | 88 | +- _LiteralOf iterates over the union members:  | 
 | 89 | +    - In non-strict mode, removes (type & {}) (the canonical "widened" type).  | 
 | 90 | +    - In strict mode, removes any non-literal (infinite template literal types).  | 
 | 91 | +    - Otherwise, keeps the literal member.  | 
 | 92 | +
  | 
 | 93 | +*/  | 
0 commit comments