joanllenas / ts.data.json Goto Github PK
View Code? Open in Web Editor NEWThis project forked from aische/jsondecoder
1.7kB JSON decoding library for Typescript
License: BSD 3-Clause "New" or "Revised" License
This project forked from aische/jsondecoder
1.7kB JSON decoding library for Typescript
License: BSD 3-Clause "New" or "Revised" License
It would be nice to have support for tuples: https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.3.3
Hi there,
I am new to front-end development and to json decoders. In my front-end TypeScript code I have the following discriminated union (DU) type:
type FooA = {
duKind: "FooA",
myPropA: string
}
type FooB = {
duKind: "FooB",
myPropB: number
}
type Foo = FooA | FooB
My back-end REST API returns either
{
"foo" : {
"fooA": {
"myPropA": "Hello World"
}
}
}
or
{
"foo" : {
"fooB": {
"myPropB": 42
}
}
}
depending on the DU case.
How can I map this to my DU types using decoders?
const fooADecoder: JsonDecoder.Decoder<FooA> = ???;
const fooBDecoder: JsonDecoder.Decoder<FooB> = ???;
const fooDecoder: JsonDecoder.Decoder<Foo> = JsonDecoder.oneOf<Foo>([
fooADecoder,
fooBDecoder
], "Foo");
I guess for the duKind
I can use JsonDecoder.constant
, but the main problem is that I have to reduce the "object nesting" from "foo": { "fooA": { "myPropA": ...}}
in JSON to {myPropA: ...}
in TypeScript.
This problem probably is not limited to DUs, but a general question of how to reduce/compress/squeeze JSON object nesting levels within a decoder.
Any help would be much appreciated, since this is a show stopper for me right now.
I just spent a fair bit of time trying to debug why an object decoder was failing, only to eventually consult the code and realize it's because the input I was passing was a JSON string rather than an actual object.
I think there are a couple of possible ways this could be better:
Let me know what your thoughts are. If you'd like I can send a PR to do some or all of these, but I want to hear what you think first.
Hi there,
my ASP.NET back end returns this json
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"status": 400,
"title": "One or more validation errors occurred.",
"errors": {
"foo": [
"The foo field is required."
],
"bar": [
"Input string '1625F' is not a valid double for bar."
]
},
"traceId": "00-a531fd30a1f7824aa76c520f60201977-073a8f282c1beb47-00"
}
for validation errors.
I modelled this in Typescript as follows:
export type ValidationProblem = Readonly<{
type: string
status: number
title: string
errors: Readonly<Map<string, readonly string[]>>
traceId: string
}>
My decoder looks like this:
const validationProblemDecoder: JsonDecoder.Decoder<ValidationProblem> =
JsonDecoder.objectStrict({
type: JsonDecoder.string,
status: JsonDecoder.number,
title: JsonDecoder.string,
errors: JsonDecoder.dictionary(JsonDecoder.array(JsonDecoder.string, "ErrorEntries"), "Errors"),
traceId: JsonDecoder.string
}, "ValidationProblem")
but I get a type error message:
Type 'Decoder<{ type: string; status: number; title: string; errors: { [name: string]: string[]; }; traceId: string; }>' is not assignable to type 'Decoder<Readonly<{ type: string; status: number; title: string; errors: Readonly<Map<string, readonly string[]>>; traceId: string; }>>'.
Type '{ type: string; status: number; title: string; errors: { [name: string]: string[]; }; traceId: string; }' is not assignable to type 'Readonly<{ type: string; status: number; title: string; errors: Readonly<Map<string, readonly string[]>>; traceId: string; }>'.
Types of property 'errors' are incompatible.
Type '{ [name: string]: string[]; }' is missing the following properties from type 'Readonly<Map<string, readonly string[]>>': clear, delete, forEach, get, and 6 more.
How can I turn the dictionary into a Map instance? I am not familiar with the index signature notation.
I just found this, and it looks very interesting. Do you have have an example of how the "hasLength" decoder would work. I can't seem to figure it out on my own.
Hi Everyone
First at all, thank you for putting this code together. I have a class with properties and gets/sets but also with extra function for specific behavior. The problem is that I get a error "...is missing the following properties from type 'DecoderObject': addOption, setOptions". Do you have any idea how to fix this?
Example
`export class Study {
private _name: string;
private _description: string;
private _goal: Goal[];
private _organizationName: string;
public readonly studyID: string;
public readonly organizationId: string;
public readonly owner: string;
public readonly ownerEmailAddress: string;
public static toApiDto(pItem: Study): ApiStudyDTO {
(...)
}
public static fromApiDTO(pItem: ApiStudyDTO): Study {
(โฆ.)
}
public get name(): string { return this._name; }
public set name(pValue: string) { this._name = pValue; }
public get description(): string { return this._description; }
public set description(pValue: string) { this._description = pValue; }
public get organizationName(): string { return this._organizationName; }
public set organizationName(pValue: string) { this._organizationName = pValue; }
public set goal(pValue: Goal[]) { this._goal = pValue; }
public get goal(): Goal[] { return this._goal; }
public addOption(pStudyOption: StudyOption) {
this.options.splice(0, 0, pStudyOption);
}
public setOptions(pStudyOptions: Array) {
this.options = pStudyOptions;
}
}`
and my JsonDecoder.Object definition is
JsonDecoder.object<Study>({ name: JsonDecoder.string, description: JsonDecoder.string, goal: JsonDecoder.array<Goal>(GoalDecoders.Goal, 'Goal[]'), organizationName: JsonDecoder.string, studyID: JsonDecoder.string, organizationId: JsonDecoder.string, owner: JsonDecoder.string, ownerEmailAddress: JsonDecoder.string, ownerName: JsonDecoder.string, studyDate: Decoders.isDate(), options: JsonDecoder.array<StudyOption>(StudyOptionDecoders.StudyOption, 'StudyOption[]') }, 'Study');
best
Hmendezm
Hey! Just adopted this library for a big project at work. Thanks for putting it together (or at least, thanks for sprucing up the thing you forked it from).
There are a few things that I think would make this a lot more usable. If you're interested, I'd be happy to submit some PRs:
.ap()
and .map()
) on Ok
and Err
.decode()
and .decodeThen()
to make them easier to use in point-free compositionsErr
to allow more flexible handling, i.e. building validation, etc.Let me know what you think! Thanks again.
I use ts.data.json to decode incoming api req.body. I have one endpoint that I expect that no parameters should be passed in. the express body parser returns an empty object. I would ideally like to verify its an empty object.
When I try.
JsonDecoder.isExactly({})
I get an error {} is not {}
which makes sense because they are different objects.
so I tried.
JsonDecoder.objectStrict<{}>({}, 'GET /');
which lets everything pass.
Just curious what you would suggest.
Thanks!
This library would be easier to use if you had an autogenerated API reference that makes it easy to see all the functions available.
For example, I just discovered that both Err and Ok have an isOk method by reading the code. These methods are useful and it'd be nice if they were easier to find. That said, the code is very readable from what little I've seen.
I could use something like JsonDecoder.object, but which returns a class instance rather than a plain object. You can work around this by having an interface FooData and a class Foo that implements FooData and takes FooData as the argument to the constructor, but I'd rather eliminate all that boilerplate.
I'm fairly certain it's possible to do this, but I'm not sure if it's possible to do this without type assertions.
Hello,
this is a great library and I want to use it in a major organization - however all our npm install
's are proxied through a corporate Artifactory instance.
This library has an unconventional for an npm packgae name with dots and not dashes (ts-data-json
๐ค ) which prevents Artifactory from letting me install it, as it thinks I'm trying to install a *.json
file.
any chance this can be renamed to a more conventional dash-separated notation?
I really appreciate this project. We have used it on a number of our projects now. The typescript generics are awesome to make sure that you are matching well.
Thanks
Add sections for the following Decoder
methods:
decode
onDecode
decodePromise
map
then
mapError
(#26)My use case: I have 1600 JSON files with complex structure that I want to type. The way I want to approach this is by iteratively running the decoder, inspecting the first error message and extending the decoder. I don't know in advance which fields those JSON files have, I want the decoder to help me in finding this out. I thus want the decoder to fail whenever it encounters an unknown object key.
Similar option exists in tcomb-validation is called strict.
The current example looks like this.
type User = {
firstname: string;
lastname: string;
};
const userDecoder = JsonDecoder.object<User>(
{
firstname: JsonDecoder.string,
lastname: JsonDecoder.string
},
'User'
);
But shouldnt it possbile to write something like this?:
const userDecoder = JsonDecoder.object(
{
firstname: JsonDecoder.string,
lastname: JsonDecoder.string
},
'User'
);
type User = ExtractDecoderType<typeof userDecoder>;
This way I dont not have to repeat myself.
So I really like ts.data.json
, and a while back I decided to open an issue in the Deno Standard Library suggesting that they include a decoder module in deno standard. Eventually, I ended up trying my hand at a PR. While the PR hasn't gotten much traction (I think one of the reasons for this is that Deno just isn't far enough along for the maintainers to focus on the standard library much), it did allow me to think critically about ts.data.json
, and learn about some other, similar libraries.
For example, some of the issues I've had with ts.data.json
:
name
argument to many decoders.I also learned that the decoder pattern is pretty popular (I imagine you already know this), and there are a number of typescript specific libraries to choose from. For example, io-ts for functional programming, or decoders which implements a pattern similar to this library. Some of the issues I've had with ts.data.json
are addressed by these other libraries, but not all of them are. Also, the library with the best support for custom error messages I found, io-ts
, is written in a functional style which doesn't appeal to me.
I decided to build out a new API to address these issues, and the repo can be seen here: https://gitlab.com/john.carroll.p/ts-decoders.
For me, the ts-decoders
repo has become my ts.data.json
2.0. It provides a more extensible API with explicit support for customizing the error messages of decoders, is tree shakable, and has full async support. If you like the API / library, I'm open to upstreaming my work. This being said, I'm not sure updating this repo with that code makes the most sense (from a user's perspective), for a few reasons:
aische/JsonDecoder
, and the ts-decoders
library is not a fork of aische/JsonDecoder
.json
decoders library. For example, you could create an AsyncDecoder
to handle decoding io from a file. This makes the ts.data.json
name a bit of a misnomer.Instead, what I was thinking (if you are open to it) is inviting you to be a maintainer of the new library with me (if you're not interested in Gitlab, where it is currently located, I'm happy to move it to Github). FYI though, while I maintain a few open source typescript libraries (rSchedule, Angular IsLoading, Angular SizeObserver), I don't have any experience working with a co-maintainer, so I imagine there will be some growing pains. Personally, that's not something I'm not worried about, but I figured I should mention it.
Anyway, if you're not interested in the new API, or if you like the current ts.data.json
API, I'm happy to go my own way with ts-decoders
. Regardless, thanks again for all your work maintaining this library!
PS: If you have any questions about the new API, why decisions were made, etc, I'm happy to answer them. The repo is fully tested, and there's a good start on documentation in the readme, but all the code isn't fully commented.
Cases with JsonDecoder.string
make the key required to be a string, but sometimes the string can be an empty one e.g. ""
. Another case, would be when the value can be any string other than certain values e.g. would fail on "STOP"
.
In my case I need to ensure empty strings for required keys fail. Is there a way to do that?
In my eyes I see 2 ways to solve this 1) an opt-in feature to fail on an empty string value in case of a required key, 2) add an optional exclude value array for strings e.g. { exclude: ["value1", "value2"] }
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.