Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON.parse() returns any, but should return Object #15225

Closed
inad9300 opened this issue Apr 17, 2017 · 12 comments
Closed

JSON.parse() returns any, but should return Object #15225

inad9300 opened this issue Apr 17, 2017 · 12 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@inad9300
Copy link

inad9300 commented Apr 17, 2017

TypeScript Version: 2.3.0

Expected behavior: JSON.parse() should return Object, as stated in MDN.

Actual behavior: JSON.parse() returns any, essentially getting rid of the useful compile-time type checks.

I realized about this while working on a project with a person new to TypeScript. She made a copy/paste mistake and ended up with a code equivalent to this:

function doSomething(data: string): Promise<any> {
    return JSON.parse(data)
}

For which TypeScript didn't show any error.

@mhegazy
Copy link
Contributor

mhegazy commented Apr 17, 2017

Object in JavaScript is similar to any. JSON.parse can return number | string| boolean | null | object | Array.

The type any here is intentional. it is meant to ease the use of the function (otherwise you will need to cast on every use). The assumption here is you will validate the input value against some criteria and that you will cast to the correct type.

@mhegazy mhegazy added the Working as Intended The behavior described is the intended behavior; this is not a bug label Apr 17, 2017
@inad9300
Copy link
Author

If that's the policy, fine then. IMHO if one wants ease of use, will go with JavaScript; TypeScript sounds to me like the option to chose when you want precisely type correctness.

@mohsen1
Copy link
Contributor

mohsen1 commented Apr 18, 2017

JSON.parse("1") === 1 is valid JS code

@inad9300
Copy link
Author

I know. I understand I was wrong on my initial suggestion, Object as the return type is not a valid solution. @mhegazy ideas were closer to a correct answer, although I don't quite get the role of object (lowercase "o") on his attempt.

After giving it some thought, I think it is not possible to correctly represent JSON.parse()'s return type using TypeScript, because it may well return an Array of Arrays recursively. Nevertheless, anything more accurate than any would be very welcomed, and a reasonable number (say, 16) of recursion levels may be represented manually, e.g.

type JsonObject =
    (number | string | boolean | null | Object) | Array<
        (number | string | boolean | null | Object) | Array<
            (number | string | boolean | null | Object) | Array<any>>>

function parseOne(): JsonObject {
    return JSON.parse('1')
}

const n: number = <number> parseOne()

I wonder what is the approach taken by TypeScript in similar recursive cases (if they exist).

@gcanti
Copy link

gcanti commented Apr 18, 2017

I think it is not possible to correctly represent JSON.parse()'s return type using TypeScript

Maybe

export type JSONObject = { [key: string]: JSON }
export interface JSONArray extends Array<JSON> {}
export type JSON = null | string | number | boolean | JSONArray | JSONObject

EDIT: TypeScript 2.2.2

@inad9300
Copy link
Author

I'm amazed that works, but with JSONArray as a type complains about a circular reference.

@aluanhaddad
Copy link
Contributor

I realized about this while working on a project with a person new to TypeScript. She made a copy/paste mistake and ended up with a code equivalent to this:

function doSomething(data: string): Promise<any> {
    return JSON.parse(data)
}

For which TypeScript didn't show any error.

Indeed, but if you are OK with explicitly returning Promise<any> it is an indication and errors are not far off anyway.

@inad9300
Copy link
Author

I don't get your point, sorry.

@mhegazy
Copy link
Contributor

mhegazy commented May 8, 2017

This issue seems to have been already addressed or is unactionable at the moment. I am auto-closing it for now.

@mhegazy mhegazy closed this as completed May 8, 2017
@rsazima
Copy link

rsazima commented Jun 7, 2017

Hi, if I understood this issue correctly, it would be the cause for the behaviour below. Is that correct?

> interface I { id: number }
> let i: I = { id: 'a' }
⨯ Unable to compile TypeScript
[eval].ts (1,5): Type '{ id: string; }' is not assignable to type 'I'.
  Types of property 'id' are incompatible.
    Type 'string' is not assignable to type 'number'. (2322)
> let i: I = JSON.parse(JSON.stringify({ id: 'a' }))
undefined
> i
{ id: 'a' }

@inad9300
Copy link
Author

inad9300 commented Jun 7, 2017

Yes.

@varshildoshi
Copy link

is it possible to create a typescript function in json??
if possible plz send me some source or link for that..

@microsoft microsoft locked and limited conversation to collaborators Jul 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

7 participants