Skip to content

Commit

Permalink
Jsonify: Improve type inference for objects with .toJSON() extend…
Browse files Browse the repository at this point in the history
…ing primitives (#690)
  • Loading branch information
nrako authored Oct 17, 2023
1 parent fcdcfe9 commit 157ed07
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 18 deletions.
36 changes: 18 additions & 18 deletions source/jsonify.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,24 @@ export type Jsonify<T> = IsAny<T> extends true
? null
: T extends JsonPrimitive
? T
: // Instanced primitives are objects
T extends Number
? number
: T extends String
? string
: T extends Boolean
? boolean
: T extends Map<any, any> | Set<any>
? EmptyObject
: T extends TypedArray
? Record<string, number>
: T extends NotJsonable
? never // Non-JSONable type union was found not empty
: // Any object with toJSON is special case
T extends {toJSON(): infer J}
? (() => J) extends () => JsonValue // Is J assignable to JsonValue?
? J // Then T is Jsonable and its Jsonable value is J
: Jsonify<J> // Maybe if we look a level deeper we'll find a JsonValue
: // Any object with toJSON is special case
T extends {toJSON(): infer J}
? (() => J) extends () => JsonValue // Is J assignable to JsonValue?
? J // Then T is Jsonable and its Jsonable value is J
: Jsonify<J> // Maybe if we look a level deeper we'll find a JsonValue
: // Instanced primitives are objects
T extends Number
? number
: T extends String
? string
: T extends Boolean
? boolean
: T extends Map<any, any> | Set<any>
? EmptyObject
: T extends TypedArray
? Record<string, number>
: T extends NotJsonable
? never // Non-JSONable type union was found not empty
: T extends []
? []
: T extends unknown[]
Expand Down
15 changes: 15 additions & 0 deletions test-d/jsonify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,21 @@ expectNotAssignable<JsonValue>(nonJsonWithToJSON);
expectAssignable<JsonValue>(nonJsonWithToJSON.toJSON());
expectAssignable<Jsonify<NonJsonWithToJSON>>(nonJsonWithToJSON.toJSON());

class NonJsonExtendPrimitiveWithToJSON extends Number {
public fixture = BigInt('42');

public toJSON(): {fixture: string} {
return {
fixture: '42n',
};
}
}

const nonJsonExtendPrimitiveWithToJSON = new NonJsonExtendPrimitiveWithToJSON();
expectNotAssignable<JsonValue>(nonJsonExtendPrimitiveWithToJSON);
expectAssignable<JsonValue>(nonJsonExtendPrimitiveWithToJSON.toJSON());
expectAssignable<Jsonify<NonJsonExtendPrimitiveWithToJSON>>(nonJsonExtendPrimitiveWithToJSON.toJSON());

class NonJsonWithToJSONWrapper {
public inner: NonJsonWithToJSON = nonJsonWithToJSON;
public override = 42;
Expand Down

0 comments on commit 157ed07

Please sign in to comment.