From ab210eb5a7dca227b4726a4a578f51c5c6d077fa Mon Sep 17 00:00:00 2001 From: Jonah Snider Date: Thu, 6 Jan 2022 02:45:47 -0800 Subject: [PATCH] Add `LiteralToPrimitive` type (#340) Co-authored-by: Sindre Sorhus --- index.d.ts | 1 + readme.md | 1 + source/literal-to-primitive.d.ts | 36 ++++++++++++++++++++++++++++++++ test-d/literal-to-primitive.ts | 12 +++++++++++ 4 files changed, 50 insertions(+) create mode 100644 source/literal-to-primitive.d.ts create mode 100644 test-d/literal-to-primitive.ts diff --git a/index.d.ts b/index.d.ts index 3b371d2d..dcfe7cf4 100644 --- a/index.d.ts +++ b/index.d.ts @@ -37,6 +37,7 @@ export {SetReturnType} from './source/set-return-type'; export {Asyncify} from './source/asyncify'; export {Simplify} from './source/simplify'; export {Jsonify} from './source/jsonify'; +export {LiteralToPrimitive} from './source/literal-to-primitive'; export { PositiveInfinity, NegativeInfinity, diff --git a/readme.md b/readme.md index 3fec1b8a..0c5f5c51 100644 --- a/readme.md +++ b/readme.md @@ -114,6 +114,7 @@ Click the type names for complete docs. - [`ConditionalPick`](source/conditional-pick.d.ts) - Like `Pick` except it selects properties from a shape where the values extend the given `Condition` type. - [`ConditionalExcept`](source/conditional-except.d.ts) - Like `Omit` except it removes properties from a shape where the values extend the given `Condition` type. - [`UnionToIntersection`](source/union-to-intersection.d.ts) - Convert a union type to an intersection type. +- [`LiteralToPrimitive`](source/literal-to-primitive.d.ts) - Convert a [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) to the [primitive type](source/primitive.d.ts) it belongs to. - [`Stringified`](source/stringified.d.ts) - Create a type with the keys of the given type changed to `string` type. - [`IterableElement`](source/iterable-element.d.ts) - Get the element type of an `Iterable`/`AsyncIterable`. For example, an array or a generator. - [`Entry`](source/entry.d.ts) - Create a type that represents the type of an entry of a collection. diff --git a/source/literal-to-primitive.d.ts b/source/literal-to-primitive.d.ts new file mode 100644 index 00000000..7220e326 --- /dev/null +++ b/source/literal-to-primitive.d.ts @@ -0,0 +1,36 @@ +/** +Given a [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) return the {@link Primitive | primitive type} it belongs to, or `never` if it's not a primitive. + +Use-case: Working with generic types that may be literal types. + +@example +``` +import {LiteralToPrimitive} from 'type-fest'; + +// No overloads needed to get the correct return type +function plus(x: T, y: T): LiteralToPrimitive { + return x + (y as any); +} + +plus('a', 'b'); // string +plus(1, 2); // number +plus(1n, 2n); // bigint +``` + +@category Type +*/ +export type LiteralToPrimitive = T extends number + ? number + : T extends bigint + ? bigint + : T extends string + ? string + : T extends boolean + ? boolean + : T extends symbol + ? symbol + : T extends null + ? null + : T extends undefined + ? undefined + : never; diff --git a/test-d/literal-to-primitive.ts b/test-d/literal-to-primitive.ts new file mode 100644 index 00000000..9d947065 --- /dev/null +++ b/test-d/literal-to-primitive.ts @@ -0,0 +1,12 @@ +import {expectType} from 'tsd'; +import {LiteralToPrimitive} from '../index'; + +// Simple usage +declare const numberPrimitive: LiteralToPrimitive<123>; +expectType(numberPrimitive); + +const symbol = Symbol('foo'); + +// Union +declare const kitchenSink: LiteralToPrimitive<123 | 123n | 'hello' | true | undefined | typeof symbol | null | {key: string}>; +expectType(kitchenSink);