Skip to content

Commit

Permalink
feat(testlab): improve typings for toJSON() helper
Browse files Browse the repository at this point in the history
Let the compiler understand toJSON's behavior for commonly used
union types like `object | null` or `unknown[] | null`.

Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
  • Loading branch information
bajtos committed Jul 4, 2019
1 parent 0edb719 commit a64e860
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
46 changes: 46 additions & 0 deletions packages/testlab/src/__tests__/unit/to-json.test.ts
Expand Up @@ -62,6 +62,42 @@ describe('toJSON', () => {
expectUndefined(value);
});

it('handles `object | null`', () => {
const input = createValueOfUnionType<object | null>({});
const output = toJSON(input);
expectComplexType<object | null>(output, input);
});

it('handles `object | undefined`', () => {
const input = createValueOfUnionType<object | undefined>({});
const output = toJSON(input);
expectComplexType<object | undefined>(output, input);
});

it('handles `object | null | undefined`', () => {
const input = createValueOfUnionType<object | null | undefined>({});
const output = toJSON(input);
expectComplexType<object | null | undefined>(output, input);
});

it('handles `unknown[] | null`', () => {
const input = createValueOfUnionType<unknown[] | null>([]);
const output = toJSON(input);
expectComplexType<unknown[] | null>(output, input);
});

it('handles `unknown[] | undefined`', () => {
const input = createValueOfUnionType<unknown[] | undefined>([]);
const output = toJSON(input);
expectComplexType<unknown[] | undefined>(output, input);
});

it('handles `unknown[] | null | undefined`', () => {
const input = createValueOfUnionType<unknown[] | null | undefined>([]);
const output = toJSON(input);
expectComplexType<unknown[] | null | undefined>(output, input);
});

it('handles classes with custom toJSON', () => {
class Customer {
private __data: object;
Expand Down Expand Up @@ -156,3 +192,13 @@ function expectNull(actual: null) {
function expectUndefined(actual: undefined) {
expect(actual).to.be.undefined();
}

function expectComplexType<T>(actual: T, expected: T) {
expect(actual).to.deepEqual(expected);
}

// A helper to force TypeScript to treat the given value as of a union type,
// e.g. treat `{}` as `object | undefined | null`.
function createValueOfUnionType<T>(value: T): T {
return value;
}
15 changes: 15 additions & 0 deletions packages/testlab/src/to-json.ts
Expand Up @@ -32,6 +32,21 @@ export function toJSON(value: number): number;
export function toJSON(value: boolean): boolean;
export function toJSON(value: string): string;

// The following overloads are required to allow TypesScript handle
// commonly used union types.

export function toJSON(value: unknown[] | null): unknown[] | null;
export function toJSON(value: unknown[] | undefined): unknown[] | undefined;
export function toJSON(
value: unknown[] | null | undefined,
): unknown[] | null | undefined;

export function toJSON(value: object | null): object | null;
export function toJSON(value: object | undefined): object | undefined;
export function toJSON(
value: object | null | undefined,
): object | null | undefined;

export function toJSON<T>(value: T) {
return JSON.parse(JSON.stringify({value})).value;
}

0 comments on commit a64e860

Please sign in to comment.