Comparing version 1.1.0 to 1.1.1
@@ -16,6 +16,10 @@ # Changelog | ||
# 1.1.0 | ||
# 1.1.1 | ||
* **Experimental** | ||
* add `optional` combinator (@gcanti) | ||
* add `clean` / `alias` functions, closes #149 (@gcanti) | ||
* add `exact` combinator (@gcanti) | ||
* the `strict` combinator is deprecated | ||
* remove `optional` combinator (@gcanti) | ||
* it doesn't play well with advanced combinators, see [here](https://github.com/gcanti/io-ts/issues/140) for a discussion | ||
@@ -22,0 +26,0 @@ # 1.0.6 |
@@ -168,9 +168,3 @@ import { Either } from 'fp-ts/lib/Either'; | ||
export declare const array: <RT extends Type<any, any, mixed>>(type: RT, name?: string) => ArrayType<RT, RT["_A"][], RT["_O"][], mixed>; | ||
export declare class OptionalType<RT extends Any, A = any, O = A, I = mixed> extends Type<A, O, I> { | ||
readonly type: RT; | ||
readonly _tag: 'OptionalType'; | ||
constructor(name: string, is: OptionalType<RT, A, O, I>['is'], validate: OptionalType<RT, A, O, I>['validate'], serialize: OptionalType<RT, A, O, I>['encode'], type: RT); | ||
} | ||
export declare const optional: <RT extends Type<any, any, mixed>>(type: RT, name?: string) => OptionalType<RT, RT["_A"] | undefined, RT["_O"] | undefined, mixed>; | ||
export declare class InterfaceType<P extends AnyProps, A = any, O = A, I = mixed> extends Type<A, O, I> { | ||
export declare class InterfaceType<P, A = any, O = A, I = mixed> extends Type<A, O, I> { | ||
readonly props: P; | ||
@@ -183,17 +177,7 @@ readonly _tag: 'InterfaceType'; | ||
} | ||
export declare type RequiredKeys<P> = { | ||
[K in keyof P]: P[K] extends OptionalType<any> ? never : K; | ||
}[keyof P]; | ||
export declare type OptionalKeys<P> = { | ||
[K in keyof P]: P[K] extends OptionalType<any> ? K : never; | ||
}[keyof P]; | ||
export declare type TypeOfProps<P extends AnyProps> = { | ||
[K in RequiredKeys<P>]: TypeOf<P[K]>; | ||
} & { | ||
[K in OptionalKeys<P>]?: TypeOf<P[K]>; | ||
[K in keyof P]: TypeOf<P[K]>; | ||
}; | ||
export declare type OutputOfProps<P extends AnyProps> = { | ||
[K in RequiredKeys<P>]: OutputOf<P[K]>; | ||
} & { | ||
[K in OptionalKeys<P>]?: OutputOf<P[K]>; | ||
[K in keyof P]: OutputOf<P[K]>; | ||
}; | ||
@@ -205,3 +189,3 @@ export interface Props { | ||
export declare const type: <P extends Props>(props: P, name?: string) => InterfaceType<P, TypeOfProps<P>, OutputOfProps<P>, mixed>; | ||
export declare class PartialType<P extends AnyProps, A = any, O = A, I = mixed> extends Type<A, O, I> { | ||
export declare class PartialType<P, A = any, O = A, I = mixed> extends Type<A, O, I> { | ||
readonly props: P; | ||
@@ -269,3 +253,3 @@ readonly _tag: 'PartialType'; | ||
export declare const readonlyArray: <RT extends Type<any, any, mixed>>(type: RT, name?: string) => ReadonlyArrayType<RT, ReadonlyArray<RT["_A"]>, ReadonlyArray<RT["_O"]>, mixed>; | ||
export declare class StrictType<P extends AnyProps, A = any, O = A, I = mixed> extends Type<A, O, I> { | ||
export declare class StrictType<P, A = any, O = A, I = mixed> extends Type<A, O, I> { | ||
readonly props: P; | ||
@@ -275,3 +259,6 @@ readonly _tag: 'StrictType'; | ||
} | ||
/** Specifies that only the given interface properties are allowed */ | ||
/** | ||
* Specifies that only the given properties are allowed | ||
* @deprecated use `exact` instead | ||
*/ | ||
export declare const strict: <P extends Props>(props: P, name?: string) => StrictType<P, TypeOfProps<P>, OutputOfProps<P>, mixed>; | ||
@@ -288,4 +275,37 @@ export declare type TaggedProps<Tag extends string> = { | ||
} | ||
export declare type Tagged<Tag extends string, A = any, O = A> = InterfaceType<TaggedProps<Tag>, A, O> | StrictType<TaggedProps<Tag>, A, O> | TaggedRefinement<Tag, A, O> | TaggedUnion<Tag, A, O> | TaggedIntersection<Tag, A, O>; | ||
export interface TaggedExact<Tag extends string> extends ExactType<Tagged<Tag>> { | ||
} | ||
export declare type Tagged<Tag extends string, A = any, O = A> = InterfaceType<TaggedProps<Tag>, A, O> | StrictType<TaggedProps<Tag>, A, O> | TaggedRefinement<Tag, A, O> | TaggedUnion<Tag, A, O> | TaggedIntersection<Tag, A, O> | TaggedExact<Tag>; | ||
export declare const taggedUnion: <Tag extends string, RTS extends Tagged<Tag, any, any>[]>(tag: Tag, types: RTS, name?: string) => UnionType<RTS, RTS["_A"]["_A"], RTS["_A"]["_O"], mixed>; | ||
export declare class ExactType<RT extends Any, A = any, O = A, I = mixed> extends Type<A, O, I> { | ||
readonly type: RT; | ||
readonly _tag: 'ExactType'; | ||
constructor(name: string, is: ExactType<RT, A, O, I>['is'], validate: ExactType<RT, A, O, I>['validate'], serialize: ExactType<RT, A, O, I>['encode'], type: RT); | ||
} | ||
export interface HasPropsRefinement extends RefinementType<HasProps, any, any, any> { | ||
} | ||
export interface HasPropsReadonly extends ReadonlyType<HasProps, any, any, any> { | ||
} | ||
export interface HasPropsIntersection extends IntersectionType<Array<HasProps>, any, any, any> { | ||
} | ||
export declare type HasProps = HasPropsRefinement | HasPropsReadonly | HasPropsIntersection | InterfaceType<any, any, any, any> | StrictType<any, any, any, any> | PartialType<any, any, any, any>; | ||
export declare function exact<RT extends HasProps>(type: RT, name?: string): ExactType<RT, TypeOf<RT>, OutputOf<RT>, InputOf<RT>>; | ||
/** Drops the runtime type "kind" */ | ||
export declare function clean<A, O = A, I = mixed>(type: Type<A, O, I>): Type<A, O, I>; | ||
export declare type PropsOf<T extends { | ||
props: any; | ||
}> = T['props']; | ||
export declare type Exact<T, X extends T> = T & { | ||
[K in ({ | ||
[K in keyof X]: K; | ||
} & { | ||
[K in keyof T]: never; | ||
} & { | ||
[key: string]: never; | ||
})[keyof X]]?: never; | ||
}; | ||
/** Keeps the runtime type "kind" */ | ||
export declare function alias<A, O, P, I>(type: PartialType<P, A, O, I>): <AA extends Exact<A, AA>, OO extends Exact<O, OO> = O, PP extends Exact<P, PP> = P, II extends I = I>() => PartialType<PP, AA, OO, II>; | ||
export declare function alias<A, O, P, I>(type: StrictType<P, A, O, I>): <AA extends Exact<A, AA>, OO extends Exact<O, OO> = O, PP extends Exact<P, PP> = P, II extends I = I>() => StrictType<PP, AA, OO, II>; | ||
export declare function alias<A, O, P, I>(type: InterfaceType<P, A, O, I>): <AA extends Exact<A, AA>, OO extends Exact<O, OO> = O, PP extends Exact<P, PP> = P, II extends I = I>() => InterfaceType<PP, AA, OO, II>; | ||
export { nullType as null, undefinedType as undefined, arrayType as Array, type as interface }; |
122
lib/index.js
@@ -367,27 +367,2 @@ "use strict"; | ||
// | ||
// optionals | ||
// | ||
var OptionalType = /** @class */ (function (_super) { | ||
__extends(OptionalType, _super); | ||
function OptionalType(name, is, validate, serialize, type) { | ||
var _this = _super.call(this, name, is, validate, serialize) || this; | ||
_this.type = type; | ||
_this._tag = 'OptionalType'; | ||
return _this; | ||
} | ||
return OptionalType; | ||
}(Type)); | ||
exports.OptionalType = OptionalType; | ||
exports.optional = function (type, name) { | ||
if (name === void 0) { name = type.name + "?"; } | ||
return new OptionalType(name, function (m) { return undefinedType.is(m) || type.is(m); }, function (i, c) { | ||
if (undefinedType.is(i)) { | ||
return exports.success(i); | ||
} | ||
else { | ||
return type.validate(i, c); | ||
} | ||
}, type.encode === exports.identity ? exports.identity : function (a) { return (undefinedType.is(a) ? a : type.encode(a)); }, type); | ||
}; | ||
// | ||
// interfaces | ||
@@ -472,6 +447,3 @@ // | ||
if (encode !== exports.identity) { | ||
var v = encode(a[k]); | ||
if (s[k] !== v) { | ||
s[k] = v; | ||
} | ||
s[k] = encode(a[k]); | ||
} | ||
@@ -780,3 +752,3 @@ } | ||
// | ||
// strict interfaces | ||
// strict types | ||
// | ||
@@ -794,25 +766,10 @@ var StrictType = /** @class */ (function (_super) { | ||
exports.StrictType = StrictType; | ||
/** Specifies that only the given interface properties are allowed */ | ||
/** | ||
* Specifies that only the given properties are allowed | ||
* @deprecated use `exact` instead | ||
*/ | ||
exports.strict = function (props, name) { | ||
if (name === void 0) { name = "StrictType<" + getNameFromProps(props) + ">"; } | ||
var loose = exports.type(props); | ||
return new StrictType(name, function (m) { return loose.is(m) && Object.getOwnPropertyNames(m).every(function (k) { return props.hasOwnProperty(k); }); }, function (m, c) { | ||
var looseValidation = loose.validate(m, c); | ||
if (looseValidation.isLeft()) { | ||
return looseValidation; | ||
} | ||
else { | ||
var o = looseValidation.value; | ||
var keys = Object.getOwnPropertyNames(o); | ||
var len = keys.length; | ||
var errors = []; | ||
for (var i = 0; i < len; i++) { | ||
var key = keys[i]; | ||
if (!props.hasOwnProperty(key)) { | ||
errors.push(exports.getValidationError(o[key], exports.appendContext(c, key, exports.never))); | ||
} | ||
} | ||
return errors.length ? exports.failures(errors) : exports.success(o); | ||
} | ||
}, loose.encode, props); | ||
var exactType = exact(exports.type(props)); | ||
return new StrictType(name, exactType.is, exactType.validate, exactType.encode, props); | ||
}; | ||
@@ -862,2 +819,3 @@ var isTagged = function (tag) { | ||
case 'RefinementType': | ||
case 'ExactType': | ||
return f(type.type); | ||
@@ -921,2 +879,64 @@ } | ||
}; | ||
// | ||
// exact types | ||
// | ||
var ExactType = /** @class */ (function (_super) { | ||
__extends(ExactType, _super); | ||
function ExactType(name, is, validate, serialize, type) { | ||
var _this = _super.call(this, name, is, validate, serialize) || this; | ||
_this.type = type; | ||
_this._tag = 'ExactType'; | ||
return _this; | ||
} | ||
return ExactType; | ||
}(Type)); | ||
exports.ExactType = ExactType; | ||
// typings-checker doesn't know Object.assign | ||
var assign = Object.assign; | ||
var getProps = function (type) { | ||
switch (type._tag) { | ||
case 'RefinementType': | ||
case 'ReadonlyType': | ||
return getProps(type.type); | ||
case 'InterfaceType': | ||
case 'StrictType': | ||
case 'PartialType': | ||
return type.props; | ||
case 'IntersectionType': | ||
return type.types.reduce(function (props, type) { return assign(props, getProps(type)); }, {}); | ||
} | ||
}; | ||
function exact(type, name) { | ||
if (name === void 0) { name = "ExactType<" + type.name + ">"; } | ||
var props = getProps(type); | ||
return new ExactType(name, function (m) { return type.is(m) && Object.getOwnPropertyNames(m).every(function (k) { return props.hasOwnProperty(k); }); }, function (m, c) { | ||
var looseValidation = type.validate(m, c); | ||
if (looseValidation.isLeft()) { | ||
return looseValidation; | ||
} | ||
else { | ||
var o = looseValidation.value; | ||
var keys = Object.getOwnPropertyNames(o); | ||
var len = keys.length; | ||
var errors = []; | ||
for (var i = 0; i < len; i++) { | ||
var key = keys[i]; | ||
if (!props.hasOwnProperty(key)) { | ||
errors.push(exports.getValidationError(o[key], exports.appendContext(c, key, exports.never))); | ||
} | ||
} | ||
return errors.length ? exports.failures(errors) : exports.success(o); | ||
} | ||
}, type.encode, type); | ||
} | ||
exports.exact = exact; | ||
/** Drops the runtime type "kind" */ | ||
function clean(type) { | ||
return type; | ||
} | ||
exports.clean = clean; | ||
function alias(type) { | ||
return type; | ||
} | ||
exports.alias = alias; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "io-ts", | ||
"version": "1.1.0", | ||
"version": "1.1.1", | ||
"description": "TypeScript compatible runtime type system for IO validation", | ||
"files": [ | ||
"lib" | ||
], | ||
"files": ["lib"], | ||
"main": "lib/index.js", | ||
@@ -12,6 +10,9 @@ "typings": "lib/index.d.ts", | ||
"lint": "tslint -p tsconfig.json src/**/*.ts test/**/*.ts", | ||
"typings-checker": "typings-checker --allow-expect-error --project typings-checker/tsconfig.json typings-checker/index.ts", | ||
"typings-checker": | ||
"typings-checker --allow-expect-error --project typings-checker/tsconfig.json typings-checker/index.ts", | ||
"mocha": "cross-env TS_NODE_CACHE=false TS_NODE_PROJECT=test/tsconfig.json mocha -r ts-node/register test/*.ts", | ||
"prettier": "prettier --no-semi --single-quote --print-width 120 --parser typescript --list-different \"{src,test}/**/*.ts\"", | ||
"fix-prettier": "prettier --no-semi --single-quote --print-width 120 --parser typescript --write \"{src,test,examples,exercises}/**/*.ts\"", | ||
"prettier": | ||
"prettier --no-semi --single-quote --print-width 120 --parser typescript --list-different \"{src,test}/**/*.ts\"", | ||
"fix-prettier": | ||
"prettier --no-semi --single-quote --print-width 120 --parser typescript --write \"{src,test,examples,exercises}/**/*.ts\"", | ||
"test": "npm run prettier && npm run lint && npm run typings-checker && npm run mocha", | ||
@@ -50,16 +51,4 @@ "clean": "rimraf lib/*", | ||
}, | ||
"tags": [ | ||
"typescript", | ||
"validation", | ||
"inference", | ||
"types", | ||
"runtime" | ||
], | ||
"keywords": [ | ||
"typescript", | ||
"validation", | ||
"inference", | ||
"types", | ||
"runtime" | ||
] | ||
"tags": ["typescript", "validation", "inference", "types", "runtime"], | ||
"keywords": ["typescript", "validation", "inference", "types", "runtime"] | ||
} |
215
README.md
@@ -71,6 +71,6 @@ [![build status](https://img.shields.io/travis/gcanti/io-ts/master.svg?style=flat-square)](https://travis-ci.org/gcanti/io-ts) | ||
// ok | ||
// validation succeeded | ||
Person.decode(JSON.parse('{"name":"Giulio","age":43}')) // => Right({name: "Giulio", age: 43}) | ||
// ko | ||
// validation failed | ||
Person.decode(JSON.parse('{"name":"Giulio"}')) // => Left([...]) | ||
@@ -136,3 +136,3 @@ ``` | ||
Static types can be extracted from runtime types with the `TypeOf` operator | ||
Static types can be extracted from runtime types using the `TypeOf` operator | ||
@@ -155,32 +155,31 @@ ```ts | ||
| Type | TypeScript | Flow | Runtime type / combinator | | ||
| --------------------- | --------------------------------------- | --------------------------------------- | ------------------------------------------------------------ | | ||
| null | `null` | `null` | `t.null` or `t.nullType` | | ||
| undefined | `undefined` | `void` | `t.undefined` | | ||
| string | `string` | `string` | `t.string` | | ||
| number | `number` | `number` | `t.number` | | ||
| boolean | `boolean` | `boolean` | `t.boolean` | | ||
| any | `any` | `any` | `t.any` | | ||
| never | `never` | `empty` | `t.never` | | ||
| object | `object` | ✘ | `t.object` | | ||
| integer | ✘ | ✘ | `t.Integer` | | ||
| array of any | `Array<mixed>` | `Array<mixed>` | `t.Array` | | ||
| array of type | `Array<A>` | `Array<A>` | `t.array(A)` | | ||
| dictionary of any | `{ [key: string]: mixed }` | `{ [key: string]: mixed }` | `t.Dictionary` | | ||
| dictionary of type | `{ [K in A]: B }` | `{ [key: A]: B }` | `t.dictionary(A, B)` | | ||
| function | `Function` | `Function` | `t.Function` | | ||
| literal | `'s'` | `'s'` | `t.literal('s')` | | ||
| partial | `Partial<{ name: string }>` | `$Shape<{ name: string }>` | `t.partial({ name: t.string })` | | ||
| optional | `name?: string` | ✘ | `name: t.optional(t.string)` | | ||
| readonly | `Readonly<T>` | `ReadOnly<T>` | `t.readonly(T)` | | ||
| readonly array | `ReadonlyArray<number>` | `ReadOnlyArray<number>` | `t.readonlyArray(t.number)` | | ||
| interface | `interface A { name: string }` | `interface A { name: string }` | `t.type({ name: t.string })` or `t.type({ name: t.string })` | | ||
| interface inheritance | `interface B extends A {}` | `interface B extends A {}` | `t.intersection([ A, t.type({}) ])` | | ||
| tuple | `[ A, B ]` | `[ A, B ]` | `t.tuple([ A, B ])` | | ||
| union | `A \| B` | `A \| B` | `t.union([ A, B ])` or `t.taggedUnion(tag, [ A, B ])` | | ||
| intersection | `A & B` | `A & B` | `t.intersection([ A, B ])` | | ||
| keyof | `keyof M` | `$Keys<M>` | `t.keyof(M)` | | ||
| recursive types | see [Recursive types](#recursive-types) | see [Recursive types](#recursive-types) | `t.recursion(name, definition)` | | ||
| refinement | ✘ | ✘ | `t.refinement(A, predicate)` | | ||
| strict/exact types | ✘ | `$Exact<{{ name: t.string }}>` | `t.strict({ name: t.string })` | | ||
| Type | TypeScript | Runtime type / combinator | | ||
| ------------------------- | --------------------------------------- | ----------------------------------------------------- | | ||
| null | `null` | `t.null` or `t.nullType` | | ||
| undefined | `undefined` | `t.undefined` | | ||
| string | `string` | `t.string` | | ||
| number | `number` | `t.number` | | ||
| boolean | `boolean` | `t.boolean` | | ||
| any | `any` | `t.any` | | ||
| never | `never` | `t.never` | | ||
| object | `object` | `t.object` | | ||
| integer | ✘ | `t.Integer` | | ||
| array of any | `Array<mixed>` | `t.Array` | | ||
| array of type | `Array<A>` | `t.array(A)` | | ||
| dictionary of any | `{ [key: string]: mixed }` | `t.Dictionary` | | ||
| dictionary of type | `{ [K in A]: B }` | `t.dictionary(A, B)` | | ||
| function | `Function` | `t.Function` | | ||
| literal | `'s'` | `t.literal('s')` | | ||
| partial | `Partial<{ name: string }>` | `t.partial({ name: t.string })` | | ||
| readonly | `Readonly<T>` | `t.readonly(T)` | | ||
| readonly array | `ReadonlyArray<number>` | `t.readonlyArray(t.number)` | | ||
| type alias | `type A = { name: string }` | `t.type({ name: t.string })` | | ||
| tuple | `[ A, B ]` | `t.tuple([ A, B ])` | | ||
| union | `A \| B` | `t.union([ A, B ])` or `t.taggedUnion(tag, [ A, B ])` | | ||
| intersection | `A & B` | `t.intersection([ A, B ])` | | ||
| keyof | `keyof M` | `t.keyof(M)` | | ||
| recursive types | see [Recursive types](#recursive-types) | `t.recursion(name, definition)` | | ||
| refinement | ✘ | `t.refinement(A, predicate)` | | ||
| exact types | ✘ | `t.exact(type)` | | ||
| strict types (deprecated) | ✘ | `t.strict({ name: t.string })` | | ||
@@ -236,5 +235,5 @@ # Recursive types | ||
# Strict/Exact interfaces | ||
# Exact types | ||
You can make an interface strict (which means that only the given properties are allowed) using the `strict` combinator | ||
You can make a runtime type alias exact (which means that only the given properties are allowed) using the `exact` combinator | ||
@@ -247,30 +246,27 @@ ```ts | ||
const StrictPerson = t.strict(Person.props) | ||
const ExactPerson = t.exact(Person) | ||
Person.decode({ name: 'Giulio', age: 43, surname: 'Canti' }) // ok | ||
StrictPerson.decode({ name: 'Giulio', age: 43, surname: 'Canti' }) // fails | ||
ExactPerson.decode({ name: 'Giulio', age: 43, surname: 'Canti' }) // fails | ||
``` | ||
# Mixing required and optional props | ||
# Strict types (deprecated) | ||
**After 1.1.0** | ||
**Note**. This combinator is deprecated, use `exact` instead. | ||
You can mix required and optional props using the `optional` combinator | ||
You can make a runtime type strict (which means that only the given properties are allowed) using the `strict` combinator | ||
```ts | ||
const A = t.type({ | ||
foo: t.string, | ||
bar: t.optional(t.number) | ||
const Person = t.type({ | ||
name: t.string, | ||
age: t.number | ||
}) | ||
type AT = t.TypeOf<typeof A> | ||
const StrictPerson = t.strict(Person.props) | ||
// same as | ||
type AT = { | ||
foo: string | ||
bar?: number | ||
} | ||
Person.decode({ name: 'Giulio', age: 43, surname: 'Canti' }) // ok | ||
StrictPerson.decode({ name: 'Giulio', age: 43, surname: 'Canti' }) // fails | ||
``` | ||
**Before 1.1.0** | ||
# Mixing required and optional props | ||
@@ -299,22 +295,2 @@ You can mix required and optional props using an intersection | ||
You can define a custom combinator to avoid the boilerplate | ||
```ts | ||
export function interfaceWithOptionals<RequiredProps extends t.Props, OptionalProps extends t.Props>( | ||
required: RequiredProps, | ||
optional: OptionalProps, | ||
name?: string | ||
): t.IntersectionType< | ||
[ | ||
t.InterfaceType<RequiredProps, t.TypeOfProps<RequiredProps>>, | ||
t.PartialType<OptionalProps, t.TypeOfPartialProps<OptionalProps>> | ||
], | ||
t.TypeOfProps<RequiredProps> & t.TypeOfPartialProps<OptionalProps> | ||
> { | ||
return t.intersection([t.interface(required), t.partial(optional)], name) | ||
} | ||
const C = interfaceWithOptionals({ foo: t.string }, { bar: t.number }) | ||
``` | ||
# Custom types | ||
@@ -350,50 +326,2 @@ | ||
# Custom combinators | ||
You can define your own combinators. Let's see some examples | ||
## The `maybe` combinator | ||
An equivalent to `T | null` | ||
```ts | ||
export function maybe<RT extends t.Any>( | ||
type: RT, | ||
name?: string | ||
): t.UnionType<[RT, t.NullType], t.TypeOf<RT> | null, t.OutputOf<RT> | null, t.InputOf<RT> | null> { | ||
return t.union<[RT, t.NullType]>([type, t.null], name) | ||
} | ||
``` | ||
## The `pluck` combinator | ||
Extracting the runtime type of a field contained in each member of a union | ||
```ts | ||
const pluck = <F extends string, U extends t.UnionType<Array<t.InterfaceType<{ [K in F]: t.Mixed }>>>>( | ||
union: U, | ||
field: F | ||
): t.Type<t.TypeOf<U>[F]> => { | ||
return t.union(union.types.map(type => type.props[field])) | ||
} | ||
export const Action = t.union([ | ||
t.type({ | ||
type: t.literal('Action1'), | ||
payload: t.type({ | ||
foo: t.string | ||
}) | ||
}), | ||
t.type({ | ||
type: t.literal('Action2'), | ||
payload: t.type({ | ||
bar: t.string | ||
}) | ||
}) | ||
]) | ||
// ActionType: t.Type<"Action1" | "Action2", "Action1" | "Action2", t.mixed> | ||
const ActionType = pluck(Action, 'type') | ||
``` | ||
# Tips and Tricks | ||
@@ -451,3 +379,3 @@ | ||
Due to an upstream [bug](https://github.com/Microsoft/TypeScript/issues/14041), VS Code might display weird types for nested types | ||
VS Code might display weird types for nested types | ||
@@ -483,1 +411,50 @@ ```ts | ||
``` | ||
## Solution: the `clean` and `alias` functions | ||
The pattern | ||
```ts | ||
// private runtime type | ||
const _NestedInterface = t.type({ | ||
foo: t.string, | ||
bar: t.type({ | ||
baz: t.string | ||
}) | ||
}) | ||
// a type alias using interface | ||
export interface NestedInterface extends t.TypeOf<typeof _NestedInterface> {} | ||
// | ||
// Two possible options for the exported runtime type | ||
// | ||
// a clean NestedInterface which drops the kind... | ||
export const NestedInterface = t.clean<NestedInterface, NestedInterface>(_NestedInterface) | ||
/* | ||
NestedInterface: t.Type<NestedInterface, NestedInterface, t.mixed> | ||
*/ | ||
// ... or an alias of _NestedInterface which keeps the kind | ||
export const NestedInterface = t.alias(_NestedInterface)<NestedInterface, NestedInterface>() | ||
/* | ||
t.InterfaceType<{ | ||
foo: t.StringType; | ||
bar: t.InterfaceType<{ | ||
baz: t.StringType; | ||
}, t.TypeOfProps<{ | ||
baz: t.StringType; | ||
}>, t.OutputOfProps<{ | ||
baz: t.StringType; | ||
}>, t.mixed>; | ||
}, NestedInterface, NestedInterface, t.mixed> | ||
*/ | ||
// you can also alias the props | ||
interface NestedInterfaceProps extends t.PropsOf<typeof _NestedInterface> {} | ||
export const NestedInterface = t.alias(_NestedInterface)<NestedInterface, NestedInterface, NestedInterfaceProps>() | ||
/* | ||
const NestedInterface: t.InterfaceType<NestedInterfaceProps, NestedInterface, NestedInterface, t.mixed> | ||
*/ | ||
``` |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
112237
1292
452