It's a typescript transformer that will transforms validate<MyType>(JSON.parse("{}"))
calls to an actual superstruct
json validator
You write that code:
import { validate } from "superstruct-ts-transformer";
type User = {
name: string;
alive: boolean;
};
const obj = validate<User>(JSON.parse('{ "name": "Me", "alive": true }'));
and it will become when you'll compile it
import * as superstruct from "superstruct";
var obj = validate_User(JSON.parse('{ "name": "Me", "alive": true }'));
function validate_User(jsonObj) {
var validator = superstruct.struct({
name: "string",
alive: "boolean"
});
return validator(jsonObj);
}
Please read this carefully as you may miss it and be really disappointed afterward
You can use babel, but you need to compile by typescript first. Babel plugin is in plans, but not the top priority right now.
You need to use ttypescript, because tsc
doesn't support custom transformers.
You can't use other module targets. Also not a show stopper, haven't seen anyone using UMD
or AMD
for applications.
No more, no less. Everything that's not representable in JSON or doesn't have a standard representation is out of the scope of this library, e.g. BigInts, functions, objects with a number indexer. You may want to keep an eye on a custom validators feature though.
npm i -D superstruct-ts-transformer
# or
yarn add --dev superstruct-ts-transformer
// you import validate function from "superstruct-ts-transformer" package
import { validate } from "superstruct-ts-transformer";
// You define or use or import your own type
type User = {
name: string;
alive: boolean;
};
// You call this validate function passing your type as generic
// and json parse result as an argument
const obj = validate<User>(JSON.parse('{ "name": "Me", "alive": true }'));
You can pass custom validators array as second argument. This custom validator should comply with 2 rules
- They must be user-defined type guards and for
- For primitives (
string
,number
,bool
) they must be nominal (type Uuid = string
won't do, typescript will see it as juststring
, rather than unique type). There's no official way to do this, but you hack your way through
// Import validate as usual
import { validate } from "superstruct-ts-transformer";
// Define a brand type
// Right here I'm using a different kind of brand hack, feel free to use any
type Uuid = string & { readonly __brand: unique symbol };
const uuidRegExp = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
// Define user-defined type guard that returns `value is Uuid` (value is name of an argument, Uuid is your brand type)
const isUuid = (value: unknown): value is Uuid =>
typeof value === "string" && !!value && uuidRegExp.test(value);
// You can also wrap imported function as user-defined type guards, e.g.
// import _isUuid from 'is-uuid'
// const isUuid = (value: unknown): value is Uuid => _isUuid
// Use this brand type
type TestType = { id: Uuid };
// Call validate function passing isUuis as second parameter array element
export const obj = validate<TestType>( w
JSON.parse('{ "id": "a4e1b0cf-2a08-4297-83f3-4db896d7e0fb" }'),
[isUuid]
);
// Transformer will use isUuid function when it will encounter Uuid type
Don't do this
const myValidate = <T>(jsonStr: string) => validate<T>(JSON.parse(jsonStr));
And don't do this
import { validate } from "superstruct-ts-transformer";
export default validate;
Basically just don't be fancy with this function, just import and use it
The usage itself is really concise, injecting custom transformer can be trickier
- Import the transformer
// Mind the destructuring
const {
createValidatorTransformer
} = require("superstruct-ts-transformer/dist/transformer");
- Add the transformer to the ts-loader config, so it'll look like this
{
test: /\.tsx?$/,
use: [{
loader: "ts-loader",
options: {
// provide your options here if you need it
getCustomTransformers: program => ({
before: [createValidatorTransformer(program)] // <-- custom transfomer configuration
})
}
}]
}
Take a look at ts-loader
docs if in hesitation.
Also take a look at tiny webpack example
To be written
- Create a
run.js
wrapper to pass the transformer programmatically
const {
createValidatorTransformer
} = require("superstruct-ts-transformer/dist/transformer");
// This is the almost the same at using `ts-node` or `node -r ts-node/register`
// However it allows us to pass transformers
// This should be executed before you start requiring ts and tsx files
require("ts-node").register({
programTransformers: program => ({
before: [createValidatorTransformer(program)] // <-- custom transfomer configuration
// don't forget that it's an array
})
});
// require your real entrypoint
require("./index.ts");
- Make use of that script by directly passing it to node, instead of using
ts-node
If you need to pass specifically options tots-node
do it inrun.js
inregister
call
// package.json
"scripts": {
"start": "node run.js"
}
In doubt take a look at tiny ts-node example