Skip to content

Commit

Permalink
fix: check type constructor arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
jedwards1211 committed Apr 7, 2021
1 parent c9b7b36 commit dfb7a13
Show file tree
Hide file tree
Showing 26 changed files with 97 additions and 8 deletions.
3 changes: 2 additions & 1 deletion src/types/ArrayType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Type from './Type'
import Type, { assertIsType } from './Type'
import Validation, { IdentifierPath } from '../Validation'

import {
Expand All @@ -18,6 +18,7 @@ export default class ArrayType<T> extends Type<Array<T>> {

constructor(elementType: Type<T>) {
super()
assertIsType(elementType, 'elementType')
this.elementType = elementType
}

Expand Down
3 changes: 3 additions & 0 deletions src/types/BooleanLiteralType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ export default class BooleanLiteralType<

constructor(value: T) {
super(value)
if (typeof value !== 'boolean') {
throw new Error(`value must be a boolean`)
}
}
}
5 changes: 4 additions & 1 deletion src/types/IntersectionType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Type from './Type'
import Type, { assertIsType } from './Type'
import Validation, { IdentifierPath } from '../Validation'
import RuntimeTypeErrorItem from '../errorReporting/RuntimeTypeErrorItem'
import ObjectType from './ObjectType'
Expand All @@ -12,6 +12,9 @@ export default class IntersectionType<T> extends Type<T> {

constructor(types: Type<any>[]) {
super()
for (let i = 0; i < types.length; i++) {
assertIsType(types[i], `types[${i}]`)
}
this.types = types
}

Expand Down
5 changes: 4 additions & 1 deletion src/types/MergedObjectType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Type from './Type'
import Type, { assertIsType } from './Type'
import ObjectType from './ObjectType'
import ObjectTypeProperty from './ObjectTypeProperty'
import Validation, { IdentifierPath } from '../Validation'
Expand All @@ -12,6 +12,9 @@ export default class MergedObjectType<T extends {}> extends Type<T> {

constructor(objects: Type<T>[], exact = true) {
super()
for (let i = 0; i < objects.length; i++) {
assertIsType(objects[i], `objects[${i}]`)
}
this.objects = objects
this.exact = exact
}
Expand Down
3 changes: 3 additions & 0 deletions src/types/NumericLiteralType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export default class NumericLiteralType<

constructor(value: T) {
super(value)
if (typeof value !== 'number') {
throw new Error(`value must be a number`)
}
}

toString(): string {
Expand Down
7 changes: 7 additions & 0 deletions src/types/ObjectType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ export default class ObjectType<T extends {}> extends Type<T> {
exact = true
) {
super()
for (let i = 0; i < properties.length; i++) {
if (!(properties[i] instanceof ObjectTypeProperty)) {
throw new Error(
`properties[${i}] must be an instance of ObjectTypeProperty`
)
}
}
this.properties = properties
this.exact = exact
properties.forEach(prop => (prop.__objectType = this))
Expand Down
11 changes: 10 additions & 1 deletion src/types/ObjectTypeProperty.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Type from './Type'
import Type, { assertIsType } from './Type'
import Validation, { IdentifierPath } from '../Validation'
import RuntimeTypeErrorItem from '../errorReporting/RuntimeTypeErrorItem'
import MissingPropertyErrorItem from '../errorReporting/MissingPropertyErrorItem'
Expand All @@ -16,6 +16,15 @@ export default class ObjectTypeProperty<

constructor(key: K, value: Type<V>, optional: boolean) {
super()
switch (typeof key) {
case 'number':
case 'string':
case 'symbol':
break
default:
throw new Error('key must be a number, string or symbol')
}
assertIsType(value, 'value')
this.key = key
this.value = value
this.optional = optional
Expand Down
4 changes: 3 additions & 1 deletion src/types/RecordType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Type from './Type'
import Type, { assertIsType } from './Type'
import Validation, { IdentifierPath } from '../Validation'

import {
Expand All @@ -23,6 +23,8 @@ export default class RecordType<

constructor(key: Type<K>, value: Type<V>) {
super()
assertIsType(key, 'key')
assertIsType(value, 'value')
this.key = key
this.value = value
}
Expand Down
3 changes: 3 additions & 0 deletions src/types/StringLiteralType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export default class StringLiteralType<

constructor(value: T) {
super(value)
if (typeof value !== 'string') {
throw new Error(`value must be a string`)
}
}

toString(): string {
Expand Down
3 changes: 3 additions & 0 deletions src/types/SymbolLiteralType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ export default class SymbolLiteralType<

constructor(value: T) {
super(value)
if (typeof value !== 'symbol') {
throw new Error(`value must be symbol`)
}
}
}
5 changes: 4 additions & 1 deletion src/types/TupleType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Type from './Type'
import Type, { assertIsType } from './Type'
import Validation, { IdentifierPath } from '../Validation'
import RuntimeTypeErrorItem from '../errorReporting/RuntimeTypeErrorItem'
import InvalidLengthErrorItem from '../errorReporting/InvalidLengthErrorItem'
Expand All @@ -10,6 +10,9 @@ export default class TupleType<T extends any[]> extends Type<T> {

constructor(types: { [Index in keyof T]: Type<T[Index]> }) {
super()
for (let i = 0; i < types.length; i++) {
assertIsType(types[i], `types[${i}]`)
}
this.types = types
}

Expand Down
5 changes: 5 additions & 0 deletions src/types/Type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { IdentifierPath } from '../Validation'
import RuntimeTypeErrorItem from '../errorReporting/RuntimeTypeErrorItem'
import RuntimeTypeError from '../errorReporting/RuntimeTypeError'

export function assertIsType(x: unknown, name: string): void {
if (!(x instanceof Type))
throw new Error(`${name} must be an instance of Type`)
}

/**
* # Type
*
Expand Down
3 changes: 2 additions & 1 deletion src/types/TypeAlias.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Type from './Type'
import Type, { assertIsType } from './Type'
import Validation, { IdentifierPath } from '../Validation'
import {
collectConstraintErrors,
Expand All @@ -15,6 +15,7 @@ export default class TypeAlias<T> extends Type<T> {

constructor(name: string, type: Type<T>) {
super()
assertIsType(type, 'type')
this.name = name
this.type = type
}
Expand Down
5 changes: 4 additions & 1 deletion src/types/UnionType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Type from './Type'
import Type, { assertIsType } from './Type'
import Validation, { IdentifierPath } from '../Validation'
import RuntimeTypeErrorItem from '../errorReporting/RuntimeTypeErrorItem'
import InvalidTypeErrorItem from '../errorReporting/InvalidTypeErrorItem'
Expand Down Expand Up @@ -64,6 +64,9 @@ export default class UnionType<T> extends Type<T> {

constructor(types: Type<any>[]) {
super()
for (let i = 0; i < types.length; i++) {
assertIsType(types[i], `types[${i}]`)
}
this.types = types
}

Expand Down
3 changes: 3 additions & 0 deletions test/alias.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ describe(`t.alias`, function() {
t.alias('Foo', t.number()).addConstraint(() => undefined).hasConstraints
).to.be.true
})
it(`requires type to be an instance of Type`, function() {
expect(() => t.alias('Foo', 2 as any)).to.throw()
})
describe(`constraints`, function() {
const PositiveNumberType = t
.alias('PositiveNumber', t.number())
Expand Down
3 changes: 3 additions & 0 deletions test/allOf.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import dedent from 'dedent-js'
import stringifyValue from '../src/errorReporting/stringifyValue'

describe(`t.allOf`, function() {
it(`requires all types to be instance of Type`, function() {
expect(() => t.oneOf(t.null(), 2 as any)).to.throw()
})
describe(`intersection of unions`, function() {
const NumberOrNull = t.allOf(
t.oneOf(t.number(), t.string(), t.null()),
Expand Down
3 changes: 3 additions & 0 deletions test/array.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { expect } from 'chai'
import dedent from 'dedent-js'

describe(`t.array`, function() {
it(`requires elementType to be an instance of Type`, function() {
expect(() => t.array(2 as any)).to.throw()
})
it(`accepts matching arrays`, function() {
t.array(t.number()).assert([1, 2, 3])
expect(t.array(t.number()).accepts([1, 2, 3])).to.be.true
Expand Down
3 changes: 3 additions & 0 deletions test/boolean.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ describe(`t.boolean`, function() {
})

describe(`t.boolean(literal)`, function() {
it(`requires value to be a boolean`, function() {
expect(() => t.boolean(2 as any)).to.throw()
})
it(`accepts literal value`, function() {
t.boolean(true).assert(true)
t.boolean(false).assert(false)
Expand Down
3 changes: 3 additions & 0 deletions test/merge.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { expect } from 'chai'
import dedent from 'dedent-js'

describe(`t.merge`, function() {
it(`requires objectTypes to be instance of Type`, function() {
expect(() => t.merge(t.object({ foo: t.number() }), 2 as any)).to.throw()
})
const BarAlias = t.alias('Bar', t.object({ bar: t.string() }))
const Merged = t.merge(
t.object({ foo: t.number() }),
Expand Down
3 changes: 3 additions & 0 deletions test/number.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ describe(`t.number`, function() {
})

describe(`t.number(literal)`, function() {
it(`requires value to be a boolean`, function() {
expect(() => t.number('1' as any)).to.throw()
})
it(`accepts literal value`, function() {
t.number(2).assert(2)
t.number(15).assert(15)
Expand Down
4 changes: 4 additions & 0 deletions test/object.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { expect } from 'chai'
import dedent from 'dedent-js'

describe(`t.object`, function() {
it(`requires values to be instance of Type`, function() {
expect(() => t.object({ name: 2 as any })).to.throw()
})

const Person = t.object({
required: {
name: t.string(),
Expand Down
3 changes: 3 additions & 0 deletions test/oneOf.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import dedent from 'dedent-js'
import stringifyValue from '../src/errorReporting/stringifyValue'

describe(`t.oneOf`, function() {
it(`requires types to be instance of Type`, function() {
expect(() => t.oneOf(t.object({ foo: t.number() }), 2 as any)).to.throw()
})
const NumberOrString = t.oneOf(t.number(), t.string())

const ObjectUnion = t.oneOf(
Expand Down
6 changes: 6 additions & 0 deletions test/record.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ import { expect } from 'chai'
import dedent from 'dedent-js'

describe(`t.record`, function() {
it(`requires key to be instance of Type`, function() {
expect(() => t.record('hello' as any, t.number())).to.throw()
})
it(`requires value to be instance of Type`, function() {
expect(() => t.record(t.string('a'), 2 as any)).to.throw()
})
const Numbers = t.record(
t.oneOf(t.string('a'), t.string('b'), t.string('c')),
t.number()
Expand Down
3 changes: 3 additions & 0 deletions test/string.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ describe(`t.string`, function() {
})

describe(`t.string(literal)`, function() {
it(`requires value to be a string`, function() {
expect(() => t.string(1 as any)).to.throw()
})
it(`accepts literal value`, function() {
t.string('foo').assert('foo')
t.string('').assert('')
Expand Down
3 changes: 3 additions & 0 deletions test/symbol.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ describe(`t.symbol`, function() {
})

describe(`t.symbol(literal)`, function() {
it(`requires value to be a string`, function() {
expect(() => t.symbol('hello')).to.throw()
})
const foo = Symbol('foo')
const bar = Symbol('bar')
it(`accepts literal value`, function() {
Expand Down
3 changes: 3 additions & 0 deletions test/tuple.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import dedent from 'dedent-js'
import stringifyValue from '../src/errorReporting/stringifyValue'

describe(`t.tuple`, function() {
it(`requires types to be instance of Type`, function() {
expect(() => t.tuple(t.object({ foo: t.number() }), 2 as any)).to.throw()
})
const TheTuple = t.tuple(t.string(), t.number(), t.boolean())
it(`accepts matching types`, function() {
for (const value of [
Expand Down

0 comments on commit dfb7a13

Please sign in to comment.