File tree Expand file tree Collapse file tree 5 files changed +93
-2
lines changed Expand file tree Collapse file tree 5 files changed +93
-2
lines changed Original file line number Diff line number Diff line change @@ -34,6 +34,7 @@ The validation errors are detailed. Adapted from the brilliant work in `flow-run
3434 - [ ` t.simpleObject({ foo: t.string() }) ` ] ( #tsimpleobject-foo-tstring- )
3535 - [ ` t.object ` ] ( #tobject )
3636 - [ ` t.record(t.string(), t.number()) ` ] ( #trecordtstring-tnumber )
37+ - [ ` t.instanceof(Date) ` ] ( #tinstanceofdate )
3738 - [ ` t.tuple(t.string(), t.number()) ` ] ( #ttupletstring-tnumber )
3839 - [ ` t.allOf(A, B) ` ] ( #tallofa-b )
3940 - [ ` t.oneOf(t.string(), t.number()) ` ] ( #toneoftstring-tnumber )
@@ -259,6 +260,10 @@ You can also use the `t.optionalNullOr(t.string())` as a shorthand for
259260
260261A validator that requires the value to be ` Record <string , number >` .
261262
263+ ### ` t .instanceOf (Date )`
264+
265+ A validator that requires the value to be an instance of ` Date ` .
266+
262267### ` t .tuple (t .string (), t .number ())`
263268
264269A validator that requires the value to be ` [string , number ]` .
Original file line number Diff line number Diff line change @@ -3,8 +3,10 @@ import { keyToString } from './keyToString'
33export default function typeOf ( value : any ) : string {
44 if ( value == null ) return String ( value )
55 if ( typeof value !== 'object' ) return typeof value
6- if ( value . constructor && value . constructor !== Object )
7- return value . constructor . name
6+ const constructor = value . prototype
7+ ? value . prototype . constructor
8+ : value . constructor
9+ if ( constructor && constructor !== Object ) return constructor . name
810 return `{\n${ Object . keys ( value )
911 . map ( key => ` ${ keyToString ( key ) } : ${ typeOf ( value [ key ] ) } ` )
1012 . join ( ',\n' ) } \n}`
Original file line number Diff line number Diff line change @@ -3,6 +3,7 @@ import AnyType from './types/AnyType'
33import ArrayType from './types/ArrayType'
44import BooleanLiteralType from './types/BooleanLiteralType'
55import BooleanType from './types/BooleanType'
6+ import InstanceOfType from './types/InstanceOfType'
67import IntersectionType from './types/IntersectionType'
78import NullLiteralType from './types/NullLiteralType'
89import UndefinedLiteralType from './types/UndefinedLiteralType'
@@ -28,6 +29,7 @@ export {
2829 ArrayType ,
2930 BooleanLiteralType ,
3031 BooleanType ,
32+ InstanceOfType ,
3133 IntersectionType ,
3234 NullLiteralType ,
3335 UndefinedLiteralType ,
@@ -171,6 +173,10 @@ export const record = <K extends string | number | symbol, V>(
171173 value : Type < V >
172174) : RecordType < K , V > => new RecordType ( key , value )
173175
176+ export const instanceOf = < T extends { new ( ...args : any [ ] ) : any } > (
177+ classType : T
178+ ) : Type < T > => new InstanceOfType ( classType )
179+
174180export const tuple = < T extends Type < any > [ ] > (
175181 ...types : T
176182) : Type < { [ Index in keyof T ] : T [ Index ] extends Type < infer E > ? E : never } > =>
Original file line number Diff line number Diff line change 1+ import * as t from './'
2+ import { expect } from 'chai'
3+ import dedent from 'dedent-js'
4+
5+ class Foo { }
6+
7+ describe ( `t.instanceOf` , function ( ) {
8+ it ( `accepts instances of class type` , function ( ) {
9+ t . instanceOf ( Date ) . assert ( new Date ( ) )
10+ t . instanceOf ( Foo ) . assert ( new Foo ( ) )
11+ expect ( t . instanceOf ( Date ) . accepts ( new Date ( ) ) ) . to . be . true
12+ expect ( t . instanceOf ( Foo ) . accepts ( new Foo ( ) ) ) . to . be . true
13+ } )
14+ it ( `rejects not instances of class type` , function ( ) {
15+ expect ( ( ) => t . instanceOf ( Date ) . assert ( { } ) ) . to . throw (
16+ t . RuntimeTypeError ,
17+ dedent `
18+ Value must be an instance of Date
19+
20+ Expected: Date
21+
22+ Actual Value: {}
23+
24+ Actual Type: {
25+
26+ }`
27+ )
28+ expect ( t . instanceOf ( Date ) . accepts ( new Foo ( ) ) ) . to . be . false
29+ expect ( ( ) => t . instanceOf ( Date ) . assert ( new Foo ( ) ) ) . to . throw (
30+ t . RuntimeTypeError ,
31+ dedent `
32+ Value must be an instance of Date
33+
34+ Expected: Date
35+
36+ Actual: Foo`
37+ )
38+ expect ( t . instanceOf ( Date ) . accepts ( new Foo ( ) ) ) . to . be . false
39+ } )
40+ } )
Original file line number Diff line number Diff line change 1+ import Type from './Type'
2+
3+ import getErrorMessage from '../getErrorMessage'
4+ import Validation , { ErrorTuple , IdentifierPath } from '../Validation'
5+
6+ export default class InstanceOfType <
7+ T extends { new ( ...args : any [ ] ) : any }
8+ > extends Type < T > {
9+ typeName = 'InstanceOfType'
10+ classType : T
11+
12+ constructor ( classType : T ) {
13+ super ( )
14+ this . classType = classType
15+ }
16+
17+ * errors (
18+ validation : Validation < any > ,
19+ path : IdentifierPath ,
20+ input : any
21+ ) : Generator < ErrorTuple , void , void > {
22+ if ( ! ( input instanceof this . classType ) ) {
23+ yield [
24+ path ,
25+ getErrorMessage ( 'ERR_EXPECT_INSTANCEOF' , this . toString ( ) ) ,
26+ this ,
27+ ]
28+ }
29+ }
30+
31+ accepts ( input : any ) : boolean {
32+ return input instanceof this . classType
33+ }
34+
35+ toString ( ) : string {
36+ return this . classType . prototype . constructor . name
37+ }
38+ }
You can’t perform that action at this time.
0 commit comments