-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Please provide a json
basic type
#1897
Comments
What kind help could the compiler provide with this? In the case where you're receiving JSON, the fact that you know everything is a string, number, boolean, array, null, or object isn't terribly useful? You could prevent yourself from passing a JSON object into an function expecting a In the case where you're emitting JSON, the type system doesn't really encapsulate all the aspects of JSON that are important. |
For the record:
|
The discussion is with respect to the case where both the client and server are written in JavaScript. For this case the JSON is shared and can be quite large and complex. There are use-cases even where Ajax is not involved where data transfer only works when the payload is string. An example of this is the HTML5 dataTransfer object. For this case having the
True if we were simply looking at how the received JSON is subsequently used. As I mentioned above, the interface Foo extends json {
image: File; // error
}
The point is classes encapsulate behaviour. JSON represents data. People who Edit: Ignore the following in the light of interface Foo extends json {
bar: string;
}
var x: Foo;
x.bar.toString(); // Error
x.bar && x.bar.toString(); // okay |
@jbondc, I'm not sure that I understand. How does that help to provide compile-time safety for JSON? |
Yes, but shouldn't break existing code ;) I'm trying to explore the implications of defining a
Yes, but with var x: int = "10"; But not so for interfaces: interface Foo extends json {
html: HtmlElement; // We would like this to be an error
} |
Since when JSONs are objects? type Json = string; |
JSON is string over the wire, but when one calls |
Yes, the JSON becomes an object and it's not JSON anymore. JSON is what you give to |
Can you elaborate? Which guys and what types? |
Seems like the problems that you described above are resolved now? Trying out this approach and it looks like it's working just fine. Also: I think this has deeper utility that just representing some arbitrary format like JSON. It enables us to more clearly distinguish data from operations on data. That's a quite fundamental piece of our domain as software developers, I don't think that would be a totally useless concept to have available and tangible in code, even if OOP still might be the norm. |
https://github.com/electricessence/TypeScript.NET/blob/master/source/JSON.d.ts This is what I have, but I'm not sure if it's adding any value really. I still have to constantly add I'm wondering if it's simply more effective to do run-time validation than be concerned with compile time constraints. I think part of the challenge is that a JSON blob can consist of either a map or an array and in those cases the indexers are different. So for example, I've had to do use And therefore still have to pass one or the other in order for it to work as show in the first link. So again, I wish there were more examples of where typing JSON helps. |
This type would be useful for data that must be able to roundtrip through JSON serialization and deserialization, such as data to be stored or otherwise faithfully reproduce across a remoting boundary. It seems to me that this simple definition of
|
I think you are on to something here 😆 but, judging by the number of Angular users on Stack Overflow who expect the simple use of TypeScript to automagically transform |
Another "me too." Here's what we ended up with: export type JSONPrimitive = string | number | boolean | null;
export type JSONValue = JSONPrimitive | JSONObject | JSONArray;
export type JSONObject = { [member: string]: JSONValue };
export interface JSONArray extends Array<JSONValue> {} Unfortunately, usage on arbitrary types requires a type assertion like |
Looks like not too late to the party. Google search didn't take long to hit on this issue & what others suggest. What I came up with is basically same as @niedzielski. Despite caveats, it's simple enough to be useful and sits a comfortable distance from settling for just In difference to @niedzielski's version, preferring Also going with End result is
Ambivalent about whether or not to separate out JsonPrimitive. |
For those finding this issue after the release of TypeScript 2.9, TypeScript now has Support for well-typed JSON imports.
|
This would still be quite useful. For example, I would like to describe a RPC interface via typescript, but assert that inputs/outputs are JSON-serializable. Unfortunately, even with the export type JSONPrimitive = string | number | boolean | null;
export type JSONValue = JSONPrimitive | JSONObject | JSONArray;
export type JSONObject = { [member: string]: JSONValue };
export interface JSONArray extends Array<JSONValue> {}
export interface ServiceDeclaration {
[key: string]: (params?: JSONObject) => Promise<JSONValue>;
}
// Expected: No errors.
interface MyService extends ServiceDeclaration {
// Error: Property 'doThing' of type '(params?: { id: string; } | undefined) => Promise<string>' is not assignable to string index type '(params?: JSONObject | undefined) => Promise<JSONValue>'.
doThing(params?: { id: string }): Promise<string>;
} One trick that gets me closer is to have template types that ask for keys explicitly, to drop the index type (e.g. the same as typescript’s built in export type IsJSONObject<TKeys extends string = string> = { [Key in TKeys]: JSONValue };
interface Foo {
id: string;
}
function doThing(params: JSONObject) {}
function doThing2<T>(params: IsJSONObject<keyof T>) {}
const foo: Foo = null as any;
// Error: Argument of type 'Foo' is not assignable to parameter of type 'JSONObject'.
// Index signature is missing in type 'Foo'.
doThing(foo);
// No error!
doThing2(foo) I'm not sure how to express that in terms of |
Just wanted to mention that this type would also be very useful for me in light of the TS 3.1 breaking change "narrowing functions now intersects {}, Object, and unconstrained generic type parameters". My existing code essentially has a type that could be either something JSON-serializable or a function; before TS 3.1, the former was blissfully expressed as an unconstrained generic, but now I need to figure out how to narrow its type, and doing that would be much easier if a JSON type existed. (On the other hand, I might be going about solving this problem in entirely the wrong way.) |
My use case is strictly typing cloneable values that can be passed to WebWorkers through |
Just bumping this up, providing my case for support for this. I can have a function, that receives something which is serialized with JSON.stringify under the hood. I don't want function's user to KNOW that out of thin air. It's really easy to make a mistake for example providing data that will be unexpectedly stringified (objects like Given in this discussion |
I wanted to create a function that would allow downloading some data as JSON for debugging purposes. For now, I am forced to use unknown, any or put together my own type, but really what I need is any JSON-serializable data just as some of the comments have suggested. An example of how I would like types on my function to behave: openDebugInfoDownloadDialog('message', { key: 'value' }); // valid
openDebugInfoDownloadDialod('message', {date: new Date(), func: () => {} }) // invalid |
TypeScript has come a long way since this issue was filed. I think it is sufficiently expressive enough to describe a json-able type, and there's a bunch of examples above of how one might do that. The one I defined in #57034 was this: export type Json =
| string
| number
| boolean
| null
| Json[]
| { [key: string]: Json }
; I don't think it warrants adding to |
It's sad ending. Still I think built-in functions |
I use Using some |
One thing that’d be great to see in the core is Lines 1137 to 1159 in b75261d
I was caught up by Curious to know if a switch to |
Wait, why would adding a JSON type for the return type of |
You'll still need to do At minimum, I agree with @kachkaev that the type should be |
It's not useless if you're going to pass it to something that takes JSON objects. For instance, as described above, a |
Those Also try |
In almost all cases you would be checking for number/string/object/null/etc explicitly, so those other branches can be ignored. And again, the fact that this would require so much type narrowing anyways just isn't worth the effort. Either trust the source outright, or use zod/etc.
Pretty sure this could just be solved with |
What about exhaustive checks?
How would you implement
|
Hi,
JSON is an important data exchange format. At present there is no explicit way to annotate an object as pure JSON. We were expecting union types to solve this problem via the following:
There are currently a number of problems with this.
Contextual typing is absent in parenthetic expression Consider contextually typing parenthesized expressions #920
Contextual typing does not flow from base to subclasses Consider contextually typing class member functions by their base class/interface members #1373
Other problems:
The first two problems look likely to be resolved, but not the last two.
This motivates the introduction of a natively supported
json
type that conforms to the JSON spec.It should be possible to derive a custom JSON object from the
json
type with non of the problems above. Furthermore, since JSON is a data exchange format it should be possible to mark fields as nullable on types deriving fromjson
(which would trigger a type guard).I am of course aware that this is all rather vague!
The text was updated successfully, but these errors were encountered: