Daniel P. Shannon
Daniel P. Shannon

Reputation: 1046

Creating a JSON interface in TypeScript without "any."

I gather that this may be impossible, given that the return type of the even the native JSON.parse function is any, but I've been puzzling over how to create a generic JSON type interface in TypeScript. There's a solution on GitHub that comes extremely close:

type JSONValue = boolean | number | string | JSONObject | JSONArray

interface JSONObject {
  [k: string]: JSONValue
}

interface JSONArray extends Array<JSONValue> {}

const json: JSONObject = {}

console.log(json.gray[9])

...but fails to compile in strict mode:

~ ❯❯❯ tsc --strict test.ts
test.ts(11,13): error TS7017: Element implicitly has an 'any' type because type 'JSONValue' has no index signature.

My understanding is that because JSONObject and JSONArray have index values, the union type JSONValue should accept one as well; clearly the compiler disagrees. I'm curious for my own edification whether there's any way around this; given that the GitHub issue was from 2015, maybe TypeScript has changed in the interim.

Thanks for any thoughts from more seasoned script typers!

Upvotes: 4

Views: 2924

Answers (1)

Gajus
Gajus

Reputation: 73788

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

type JsonValue =
  | null
  | boolean
  | number
  | string
  | JsonValue[]
  | JsonObject;

const stringify = (subject: JsonObject) => {};

stringify({
  foo: 'bar',
});

stringify({
  // @ts-expect-error
  foo: () => {}
});

https://www.typescriptlang.org/play?ssl=20&ssc=4&pln=1&pc=1#code/C4TwDgpgBAUgzgewHYHkBGArCBjYUC8UA3lANoDWEIAXFHMAE4CWSA5gLq3zIBqAhgBsArtAC+AbgCwAKBmhIsREn7Do+GVCgAfKEiECBG7VDQIEAiHyRGdegLZoIDG3UYtWL7ssEjS7T0roWLhSstLYyPSuzGxMAGYgBFAAFHBCmDjAXIEZuACUBAB8xBIyMvQxrPEgyURGcWa0AORofAxNADQyonmh5W6xCbVGAPQjUAACwHAAtBAAHpC4cwwMCM7Smg0ItMkF+MVEot29QA

Upvotes: 4

Related Questions