{"id":26502825,"url":"https://github.com/grassator/jdaughter","last_synced_at":"2026-05-18T08:06:13.692Z","repository":{"id":57279907,"uuid":"113235172","full_name":"grassator/jdaughter","owner":"grassator","description":"Typesafe JSON decoding for TypeScript","archived":false,"fork":false,"pushed_at":"2018-07-25T19:00:03.000Z","size":75,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-09T06:08:18.211Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grassator.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-05T21:31:23.000Z","updated_at":"2020-02-10T15:46:25.000Z","dependencies_parsed_at":"2022-09-09T14:50:11.738Z","dependency_job_id":null,"html_url":"https://github.com/grassator/jdaughter","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grassator%2Fjdaughter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grassator%2Fjdaughter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grassator%2Fjdaughter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grassator%2Fjdaughter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grassator","download_url":"https://codeload.github.com/grassator/jdaughter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244671871,"owners_count":20491269,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-20T18:35:39.947Z","updated_at":"2026-05-18T08:06:08.645Z","avatar_url":"https://github.com/grassator.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jdaughter\n\n[![Build Status](https://travis-ci.org/grassator/jdaughter.svg?branch=master)](https://travis-ci.org/grassator/jdaughter)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nThis project provides type-safe decoding (validation) of a JSON structure. Here's a quick sample using `fetch` API:\n\n```typescript\nimport * as D from \"jdaughter\";\n\nconst decoder =\n  D.object({\n    origin: D.string,\n    headers: D.object({ Host: D.string })\n  });\n\nfetch('https://httpbin.org/anything')\n    .then(response =\u003e response.json())\n    .then(data =\u003e D.decode(decoder, data))\n    .then(data =\u003e {\n      // Here the data has correct structure (and type in TypeScript)\n      // {origin: string, headers: {Host: string}}\n      console.log(data.headers);\n    });\n```\n\nYou can see more examples in the tests.\n\n\u003e NOTE: Currently this library only provides decoding (validation) of the exact structure of the target value, not the direct parsing from the JSON.\n\n## Motivation\n\nMost of the recommendations on StackOverflow and other community sources simply recommend assuming a parsed JSON response from an API is whatever we *believe* it should be. This is very unsafe, as data coming from the API has the same danger level as one directly inputted by the user. Besides the purposely malicious data, remote API might change or malfunction, resulting in incorrect data sent over the wire.\n\nAll of this things may result in security issues or incorrect behavior of your application that can be quite hard to discover as the data from the API may only be accessed deep inside the application.\n\n`jdaughter` fixes the issue by providing runtime type assertions through an easy-to-use API. It has zero dependencies and can be used in any ECMAScript 2015 compatible (or transpiled) environment or in TypeScript projects.\n\n## TypeScript Support\n\n\u003e `jdaughter` requires TypeScript 2.8+ as it make use of conditional types.\n\nA big feature of `jdaughter` is not only ensuring correct structure of the decoded value, but also the correct type. This means that if you ensure that every incoming value in the application is passing through a decoder you will have a much higher degree of certainty that the program won't explode at runtime. Technically if you are not using type corecions and avoid things that throw, you should be completely safe.\n\nIf you have a decoder and want to get the type of the decoded type, this can be done as follows:\n\n```typescript\nimport { DecodedType, array, number } from \"jdaughter\";\n\nconst arrayDecoder = array(number);\n\ntype ArrayOfNumbers = DecodedType\u003ctypeof arrayDecoder\u003e;\n```\n\n## Usage\n\n### Importing\n\nCurrently `jdaughter` can be imported as follows in Commonjs:\n\n```js\nconst Decoder = require(\"jdaughter\")\n```\n\nOr like this in ES2015 modules or TypeScript:\n\n```js\nimport * as Decoder from \"jdaughter\";\n```\n\n### Primitive Decoders\n\nTo be able to decode and ensure the basic JSON types, there are pre-defined decoders available inside the library:\n\n```js\nimport { undefined_, null_, boolean, number, string } from \"jdaughter\";\n```\n\n### `Date` Decoder\n\nIt is quite common for APIs to provide date inside a JSON response, however JSON does not provide one. `date` expects a string value formatted as ISO 8601.\n\n```js\nimport { decode, date, decode } from \"jdaughter\";\nconst date = decode(date, \"2017-12-03T18:25:43+02:00\");\n```\n\n### Array Decoder\n\nAllows to decode arrays of another type, which can be primitive:\n\n```js\nimport { array, number, decode } from \"jdaughter\";\nconst arrayOfNumbersDecoder = array(number);\nconst result = decode(arrayOfNumbersDecoder, [1, 2, 3]);\n```\n\nOr it can be complex type, including a nested arrays\n\n```js\nimport { array, number, decode } from \"jdaughter\";\nconst arrayOfArraysOfNumbersDecoder = array(array(number));\nconst result = arrayOfArraysOfNumbersDecoder.decode([[1], [2], [3]]);\n```\n\n### Object Decoder\n\nAllows to decode objects with a pre-defined sets of fields, including nested objects or arrays:\n\n```js\nimport { object, array, string, decode } from \"jdaughter\";\nconst decoder =\n    object({\n      foo: string,\n      bar: object({\n        nested_bar: string\n      }),\n      arr: array(string)\n    });\nconst result = decode(decoder, {\n  foo: 'foo',\n  bar: {\n    'nested_bar': 'bar'\n  },\n  arr: [1, 2, 3]\n});\n```\n\nIt is also possible to specify a mapping function from the field name you want in the decoded object to the one in the raw JSON. For example it is quite common for a JSON apis to have snake_case fields, while it is preferred to have camelCase in JavaScript:\n\n```js\nimport { object, string, decode } from \"jdaughter\";\nimport { snakeCase } from 'lodash';\n\nconst decoder = object({ fooBar: string }, snakeCase);\nconst result = decode(decoder, {\"foo_bar\": \"foo\"});\n```\n\n### Dictionary Decoder\n\nSome APIs use JSON objects as dictionaries either from strings to some values, for example strings to booleans:\n\n```js\nimport { dictionary, string, boolean, decode } from \"jdaughter\";\nconst decoder = dictionary(string, boolean);\nconst result = decode(decoder, {\n  foo: false,\n  bar: true\n});\n```\n\n\u003e When used in TypeScript this will produce correct indexed type `{[key: string]: boolean}`\n\n### Either Decoder\n\nIf a field can contain values of varying types, it can be represented with `either` decoder. A common case where an object is nullable:\n\n```js\nimport { either, object, string, null_, decode } from \"jdaughter\";\nconst objectOrNull = either(object({ foo: string }), null_);\nconst result = decode(objectOrNull, null);\n```\n\nSince decoders are arbitrarily composable, you can also compose `either` with itself to describe fields that can have more than 2 possible types:\n\n```js\nimport { either, string, number, boolean } from \"jdaughter\";\nconst stringNumberOrBoolean = either(string, either(number, boolean));\n```\n\n\n### Always Decoder\n\n`always` is a decoder that does not inspect actual value and instead always gives one it was initialized with. While not really useful by itself, it allows for having default values when used together with `either`:\n\n```js\nimport { either, string, always, decode } from \"jdaughter\";\nconst stringWithDefault = either(string, always(\"\"));\nconst result = decode(stringWithDefault, null); // \"\"\n```\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2017 Dmitriy Kubyshkin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrassator%2Fjdaughter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrassator%2Fjdaughter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrassator%2Fjdaughter/lists"}