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 Jsonifiable type #492

Merged
merged 14 commits into from
Nov 5, 2022
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export type {SetReturnType} from './source/set-return-type';
export type {Asyncify} from './source/asyncify';
export type {Simplify} from './source/simplify';
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 {
Expand Down
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ Click the type names for complete docs.
### JSON

- [`Jsonify`](source/jsonify.d.ts) - Transform a type to one that is assignable to the `JsonValue` type.
- [`Jsonifiable`](source/jsonifiable.d.ts) - Matches a value that can be losslessly converted to JSON.
- [`JsonPrimitive`](source/basic.d.ts) - Matches a JSON primitive.
- [`JsonObject`](source/basic.d.ts) - Matches a JSON object.
- [`JsonArray`](source/basic.d.ts) - Matches a JSON array.
Expand Down
37 changes: 37 additions & 0 deletions source/jsonifiable.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type {JsonPrimitive, JsonValue} from './basic';

type JsonifiableObject = {[Key in string]?: Jsonifiable} | {toJSON: () => Jsonifiable};
type JsonifiableArray = readonly Jsonifiable[];

/**
Matches a value that can be losslessly converted to JSON.

Can be used to type values that you expect to pass to `JSON.stringify`.

`undefined` is allowed in object fields (for example, `{a?: number}`) as a special case even though `JSON.stringify({a: undefined})` is `{}` because it makes this class more widely useful and checking for undefined-but-present values is likely an anti-pattern.

@example
```
import type {Jsonifiable} from 'type-fest';

// @ts-expect-error
const error: Jsonifiable = {
map: new Map([['a', 1]]),
};

JSON.stringify(error);
//=> {"map": {}}

const good: Jsonifiable = {
number: 3,
date: new Date(),
missing: undefined,
}

JSON.stringify(good);
//=> {"number": 3, "date": "2022-10-17T22:22:35.920Z"}
```

@category JSON
*/
export type Jsonifiable = JsonPrimitive | JsonifiableObject | JsonifiableArray;
30 changes: 30 additions & 0 deletions test-d/jsonifiable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {expectAssignable, expectNotAssignable} from 'tsd';
import type {Jsonifiable} from '..';

expectAssignable<Jsonifiable>(1);
expectAssignable<Jsonifiable>('');
expectAssignable<Jsonifiable>(null);
expectAssignable<Jsonifiable>(new Date());
expectAssignable<Jsonifiable>({a: new Date()});
expectAssignable<Jsonifiable>([new Date()]);
expectAssignable<Jsonifiable>({a: undefined});
expectAssignable<Jsonifiable>([1, 2, 3] as const);
expectAssignable<Jsonifiable>({a: new Date()} as const);
expectAssignable<Jsonifiable>({a: {deeply: {nested: {toJsonObject: new Date()}}}});
expectAssignable<Jsonifiable>({toJSON: () => new Date()});
expectAssignable<Jsonifiable>({
toJSON() {
return {
foo: {
toJSON() {
return {bar: 'bar'};
},
},
};
},
});

expectNotAssignable<Jsonifiable>(undefined);
expectNotAssignable<Jsonifiable>(new Map());
expectNotAssignable<Jsonifiable>({a: new Map()});
expectNotAssignable<Jsonifiable>([new Map()]);