type-fest icon indicating copy to clipboard operation
type-fest copied to clipboard

Make `JsonObject` work as expected with TS 4.4 `--exactOptionalPropertyTypes`

Open voxpelli opened this issue 3 years ago • 2 comments

#269 brought to my attention that #65 changed the JsonObject so that all keys are marked as optional.

Before TypeScript 4.4 a { foo?: string} and a { foo?: string|undefined } was always treated as equal, so #65 made sense then.

But with TS 4.4 the new --exactOptionalPropertyTypes config was introduced, which (correctly )no longer treats { foo?: string} as equal to { foo?: string|undefined }.

For some reason though, the change introduced in #65 still gets treated in the old way: https://github.com/sindresorhus/type-fest/blob/6b6d81ce894517268391db63b3d6538e971c8126/source/basic.d.ts#L22

I would propose reverting #65 and moving back to:

export type JsonObject = {[key: string]: JsonValue};

I think it behaves more correctly, as can be seen in this playground.

voxpelli avatar Sep 22 '21 23:09 voxpelli

I would propose reverting #65 and moving back to:

👍

sindresorhus avatar Sep 24 '21 09:09 sindresorhus

Since this style of JsonObject has been out for so long, I think we should maybe split it up into two types (names for illustration purposes only) to not break things unnecessarily:

  1. JsonObjectStringifiable – one that behaves like today's JsonObject. Would represent a value intended for JSON.stringify() where { foo: undefined } and plain {} are functionally equivalent.
  2. JsonObjectParsed – one that represents an actual parsed JSON value, coming from eg. JSON.parse() where undefined as a value is impossible.

Relatedly:

JSON.stringify(['foo', 1, undefined, 2])

Outputs:

["foo",1,null,2]

So I guess JsonArray should also really have a one type focused on serialization/stringification and another that properly reflects the values available in the JSON itself.

(If one wants to go crazy, then such serialization/stringification versions of the types could even include support for the toJSON method on objects)

voxpelli avatar Mar 22 '22 10:03 voxpelli

I would propose reverting #65 and moving back to:

export type JsonObject = {[key: string]: JsonValue};

FI: A version that supports both cases (playground) added in #465.

export type JsonObject = {[Key in string]: JsonValue} & {[Key in string]?: JsonValue | undefined};

skarab42 avatar Sep 15 '22 08:09 skarab42