Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LiteralToPrimitiveDeep Type #584

Merged
merged 11 commits into from Apr 4, 2023
1 change: 1 addition & 0 deletions index.d.ts
Expand Up @@ -55,6 +55,7 @@ export type {Jsonify} from './source/jsonify';
export type {Jsonifiable} from './source/jsonifiable';
export type {Schema} from './source/schema';
export type {LiteralToPrimitive} from './source/literal-to-primitive';
export type {LiteralToPrimitiveDeep} from './source/literal-to-primitive-deep';
export type {
PositiveInfinity,
NegativeInfinity,
Expand Down
1 change: 1 addition & 0 deletions readme.md
Expand Up @@ -157,6 +157,7 @@ Click the type names for complete docs.
- [`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.
- [`LiteralToPrimitiveDeep`](source/literal-to-primitive-deep.d.ts) - Like `LiteralToPrimitive` except it converts literal types inside an object or array deeply.
- [`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.
Expand Down
36 changes: 36 additions & 0 deletions source/literal-to-primitive-deep.d.ts
@@ -0,0 +1,36 @@
import type {LiteralToPrimitive} from './literal-to-primitive';
import type {OmitIndexSignature} from './omit-index-signature';

/**
Like `LiteralToPrimitive` except it converts literal types inside an object or array deeply.

For example, given a constant object, it returns a new object type with the same keys but with all the values converted to primitives.

@see LiteralToPrimitive

Use-case: Deal with data that is imported from a JSON file.

@example
```
import type {LiteralToPrimitiveDeep, TsConfigJson} from 'type-fest';
import tsconfig from 'path/to/tsconfig.json';

function doSomethingWithTSConfig(config: LiteralToPrimitiveDeep<TsConfigJson>) { ... }

// No casting is needed to pass the type check
doSomethingWithTSConfig(tsconfig);

// If LiteralToPrimitiveDeep is not used, you need to cast the imported data like this:
doSomethingWithTSConfig(tsconfig as TsConfigJson);
```

@category Type
@category Object
*/
export type LiteralToPrimitiveDeep<T> = T extends object
? T extends Array<infer U>
? Array<LiteralToPrimitiveDeep<U>>
: {
[K in keyof OmitIndexSignature<T>]: LiteralToPrimitiveDeep<T[K]>;
}
: LiteralToPrimitive<T>;
54 changes: 54 additions & 0 deletions test-d/literal-to-primitive-deep.ts
@@ -0,0 +1,54 @@
import {expectType} from 'tsd';
import type {IsEqual, LiteralToPrimitiveDeep} from '../index';

type LiteralObject = {
a: string;
b: number;
c: boolean;
d: {
e: bigint;
f: symbol;
g: {
h: string[];
i: {
j: boolean;
k: {
l: 1;
m: 'hello';
o: [1, 2, 3];
p: ['a', 'b', 'c'];
q: [1, 'a', true];
};
};
};
};
};

type PrimitiveObject = {
a: string;
b: number;
c: boolean;
d: {
e: bigint;
f: symbol;
g: {
h: string[];
i: {
j: boolean;
k: {
l: number;
m: string;
o: number[];
p: string[];
q: Array<number | string | boolean>;
};
};
};
};
};

const typeEqual: IsEqual<
LiteralToPrimitiveDeep<LiteralObject>,
PrimitiveObject
> = true;
expectType<true>(typeEqual);