From 17b0235699b6898d3a97948d9752c87697eb1ca3 Mon Sep 17 00:00:00 2001 From: Darcy Parker <945058+darcyparker@users.noreply.github.com> Date: Wed, 30 Mar 2022 04:56:55 -0400 Subject: [PATCH] `Jsonify`: Handle `undefined` in array (#310) --- source/jsonify.d.ts | 9 ++++++++- test-d/jsonify.ts | 12 ++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/source/jsonify.d.ts b/source/jsonify.d.ts index 10bdf5e0b..20c03a7c7 100644 --- a/source/jsonify.d.ts +++ b/source/jsonify.d.ts @@ -3,6 +3,13 @@ import {JsonPrimitive, JsonValue} from './basic'; // Note: The return value has to be `any` and not `unknown` so it can match `void`. type NotJsonable = ((...args: any[]) => any) | undefined; +// Note: Handles special case where Arrays with `undefined` are transformed to `'null'` by `JSON.stringify()` +// Only use with array members +type JsonifyArrayMember = + T extends undefined ? + null | Exclude : + Jsonify; + /** Transform a type to one that is assignable to the `JsonValue` type. @@ -64,7 +71,7 @@ type Jsonify = ? T extends JsonPrimitive ? T // Primitive is acceptable : T extends Array - ? Array> // It's an array: recursive call for its children + ? Array> // It's an array: recursive call for its children : T extends object ? T extends {toJSON(): infer J} ? (() => J) extends (() => JsonValue) // Is J assignable to JsonValue? diff --git a/test-d/jsonify.ts b/test-d/jsonify.ts index ee467fc58..dd51f51cb 100644 --- a/test-d/jsonify.ts +++ b/test-d/jsonify.ts @@ -123,6 +123,18 @@ const nonJsonWithInvalidToJSON = new NonJsonWithInvalidToJSON(); expectNotAssignable(nonJsonWithInvalidToJSON); expectNotAssignable(nonJsonWithInvalidToJSON.toJSON()); +// Special cases of Array with `undefined` member +// `[undefined]` is not JSON because it contains non JSON value `undefined` +// However `JSON.parse(JSON.stringify())` transforms array members of `undefined` to `null` +expectNotAssignable([undefined]); +declare const parsedStringifiedArrayWithUndefined1: Jsonify; // = JSON.parse(JSON.stringify([undefined])); +expectType(parsedStringifiedArrayWithUndefined1); +expectAssignable(parsedStringifiedArrayWithUndefined1); +expectNotAssignable([undefined, 1]); +declare const parsedStringifiedArrayWithUndefined2: Jsonify<[undefined, number]>; +expectType>(parsedStringifiedArrayWithUndefined2); +expectAssignable(parsedStringifiedArrayWithUndefined2); + // Test that optional type members are not discarded wholesale. interface OptionalPrimitive { a?: string;