Open
Description
Search Terms
- JSON
Suggestion
Type annotation for JSON in a string.
Use Cases
Let's say you have a string which contains valid JSON object, like so:
const json = '{"hello": "world"}';
How can you type annotate the json
variable? Currently, you can mark it as a string
:
const json: string = '{"hello": "world"}';
Instead there could be some TypeScript language feature that helps with typing JSON in a string more precisely, for example:
const json: JSON {hello: string} = '{"hello": "world"}';
Examples
Specify that string contains valid JSON.
let json: JSON any;
let json: JSON; // shorthand
Add typings to an HTTP response body.
let responseBody: JSON {ping: 'pong'} = '{"ping": "pong"}';
Add type safety to JSON.parse()
method.
let responseBody: JSON {ping: 'pong'} = '{"ping": "pong"}';
let {ping} = JSON.parse(responseBody);
typeof ping // 'pong'
JSON cannot contain complex types.
type Stats = JSON {mtime: Date}; // Error: Date is not a valid JSON type.
Doubly serialized JSON.
let response: JSON {body: string} = '{"body": "{\"userId\": 123}"}';
let fetchUserResponse: JSON {body: JSON {userId: number}} = response;
Get type of serialized JSON string using jsontype
keyword.
type Response = JSON {body: string, headers: object};
type ResponseJson = jsontype Response; // {body: string, headers: object}
type ResponseBody = ResponseJson['body']; // string
type ResponseBody = (jsontype Response)['body']; // string
Specify that variable is JSON-serializable.
let serializable: jsontype JSON = {hello: 'world'};
JSON.serialize(serializable); // OK
let nonserializable: object = {hello: 'world'};
JSON.serialize(nonserializable); // Error: 'nonserializable' might not be serializable.
Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript / JavaScript codeThis wouldn't change the runtime behavior of existing JavaScript codeThis could be implemented without emitting different JS based on the types of the expressionsThis isn't a runtime feature (e.g. new expression-level syntax)
Syntax Alternatives
type ResponseRaw = JSON {ping: 'pong'};
type ResponseRaw = json {ping: 'pong'};
type ResponseRaw = string {ping: 'pong'};
type ResponseRaw = json_string {ping: 'pong'};
type ResponseRaw = JSON<{ping: 'pong'}>;
type ResponseRaw = JSON({ping: 'pong'});
type Response = jsontype Response; // {ping: 'pong'}
type Response = typeof Response; // {ping: 'pong'}
type Response = parsed(Response); // {ping: 'pong'}
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
[-]JSON field[/-][+]JSON type[/+]weswigham commentedon Oct 16, 2018
It seems like you want, generally, refinements on string types. In the vein of #6579 (for specifically regex refinements) or #4895 (for arbitrary nominal refinements).
streamich commentedon Oct 16, 2018
@weswigham refinements on
string
type, yes, but this proposal deals specifically with JSON, which is a common use case and—I believe—specific enough that it could actually be implemented.RyanCavanaugh commentedon Oct 16, 2018
What are the use cases for writing JSON strings in code instead of writing them as parsed literals?
streamich commentedon Oct 16, 2018
@RyanCavanaugh I have plenty of mock data for tests as JSON in strings, when you receive response from and API it could be JSON in a string, when you read from a file it could be
.json
. I'm sure there a re plenty more examples.Doubly, triply, etc. serialized JSON is another example.
RyanCavanaugh commentedon Oct 16, 2018
What I mean is, if you're writing the code, why are you writing them in the error-prone
"{ 'x': 'y'}"
form instead of the easier{ x: 'y' }
form?streamich commentedon Oct 16, 2018
@RyanCavanaugh I am not, but sometimes you receive your data in that form and you have to deal with it. For example, here is a typical AWS SQS response example:
(I have removed some fields for brevity. Also, I hope all the escapings are correct. :) )
The above is basically dobly-serialized JSON in
Messages[0].Body
field. I have no control of this format, but I would like to type annotate it somehow. For example it could be done like so:RyanCavanaugh commentedon Oct 16, 2018
Makes sense - but in that case, we can't really do any valuable typechecking of that JSON at compile-time. Or are you saying you're copying the JSON responses into your test files? Just trying to understand
streamich commentedon Oct 16, 2018
Sure, but code can be annotated at dev time so developer can get all the code completion and error messages that are obvious from static code analysis. For example:
Yes.
weswigham commentedon Oct 16, 2018
So you're saying it'd be useful coupled with a
JSON.parse
overload along the lines ofstreamich commentedon Oct 16, 2018
@weswigham Exactly!
weswigham commentedon Oct 16, 2018
Along the lines of what people have said in #4895, you can get pretty close with branded strings today:
there's no automatic creation of them and no automatic validation that your string actually meets the constraint you want the type to imply, but you can flow the type around, at least.
streamich commentedon Oct 16, 2018
@weswigham How would you annotate
JSON.stringify
method using branded strings?streamich commentedon Oct 16, 2018
OK, if anyone is interested, here is what I did:
Autocompletion works:
streamich commentedon Oct 16, 2018
Autocompletion for above mentioned example works, too:
streamich commentedon Oct 31, 2018
BTW, create this tiny NPM package if anyone needs branded JSON strings:
https://github.com/streamich/ts-brand-json
NotWearingPants commentedon Nov 19, 2019
It is faster to use
JSON.parse
of a string literal than to use a JSON object literal:https://v8.dev/blog/cost-of-javascript-2019#json
So this feature is now a bit more useful (although it is better if the compiler will generate the
JSON.parse
itself when it sees a JSON literal)