Skip to content

Lib type definition for JSON.stringify asserts incorrect return type #55436

@rewento

Description

@rewento

⚙ Compilation target

ES2022

⚙ Library

es2022

Missing / Incorrect Definition

ECMA-262 2011 (5.1) indicates that the value returned by a call of the JSON.stringify method may be a string or undefined. See Step 11 of the "abstract operation Str(key, holder)" outlined here in the specification.

ECMA-262 2022 (13) indicates the same. See Note #5 under the specification's JSON.stringify section.

Mozilla Developer Network documentation reiterates the same: "JSON.stringify() can return undefined when passing in "pure" values like JSON.stringify(() => {}) or JSON.stringify(undefined)".

According to the aforementioned specifications and documentation, this is the union type that includes all values that, when supplied as the first argument in a call of JSON.stringify, elicit an undefined return value: Function | Symbol | undefined.

Executing these statements in any JavaScript runtime environment confirms JavaScript engine adherence to the behavior of JSON.stringify described in the specifications and documentation:

JSON.stringify(undefined); // Returns undefined.
JSON.stringify(function() {}); // Returns undefined.
JSON.stringify(() => {}); // Returns undefined.
JSON.stringify(Symbol()); // Returns undefined.

However, the JSON interface included among the TypeScript lib type definitions asserts that a call of the stringify method will return a value of type string in all cases and never an undefined value.

interface JSON {
    // ...
    // Neither signature includes undefined in its return type.
    stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
    stringify(value: any, replacer?: (number | string)[] | null, space?: string | number): string;
}

The JSON interface should be modified so that its signatures for the stringify method acknowledge the cases in which the method may return undefiend as well as the cases in which it will return undefined. For example:

interface JSON {
    // ...
    // Will return an undefined value.
    stringify(value: Function | Symbol | undefined, replacer?: (this: any, key: string, value: any) => any, space?: string | number): undefined;
    // Will return either a string or undefined.
    stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string | undefined;
    // Will return an undefined value.
    stringify(value: Function | Symbol | undefined, replacer?: (number | string)[] | null, space?: string | number): undefined;
   // Will return either a string or undefined.
    stringify(value: any, replacer?: (number | string)[] | null, space?: string | number): string | undefined;
}

Sample Code

// Type of example variables reported by TypeScript compiler is string, which is inaccurate. The correct type is undefined.
const example1 = JSON.stringify(function(){});
const example2 = JSON.stringify(() => {});
const example3 = JSON.stringify(Symbol());
const example4 = JSON.stringify(undefined);

// Playground: https://www.typescriptlang.org/play?ts=5.3.0-dev.20230819#code/PTAEBUE8AcFNQPYDNSwB4EMC20A28A3DAJwEsMAjfAZ1GNmgWIBdYATUCyCGWAZQDGZaM1ACEOUvmKhStaszIA7AOYAaUAHcAFqQHbZtUkowCBAV2IZWAOgjb444vQGjmvQ6HNK2sJMfYbAChxJQVUTBx8AEZQAF5QACk+AHkAORsFZRVSJEgACiRvV1IEJXyASgBvAF8KgG4QsvD0bDxYACZ4pNSMrOMcvPzK+IA+UFqGprDRVqjYAGZu5PTMxQHcgr5ILAoEXEqp0JbI9oAWZd617M38719-JXYpoKA

Documentation Link

ECMA-262 2022 Section 15.12.3

Mozilla Developer Network documentation of JSON.stringify.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions