From dde7d3593743b72e7923ebafe4de0561d261d0e7 Mon Sep 17 00:00:00 2001 From: majo44 Date: Mon, 28 Oct 2019 13:08:10 +0100 Subject: [PATCH 1/7] Adding typescript declarations. --- .npmignore | 3 + CHANGELOG.md | 4 + package.json | 13 ++- types/ArrayType.d.ts | 17 +++ types/BooleanType.d.ts | 11 ++ types/DateType.d.ts | 14 +++ types/NumberType.d.ts | 17 +++ types/ObjectType.d.ts | 13 +++ types/Schema.d.ts | 26 +++++ types/SchemaDeclaration.d.ts | 24 +++++ types/StringType.d.ts | 24 +++++ types/Type.d.ts | 17 +++ types/index.d.ts | 49 +++++++++ types/test.ts | 197 +++++++++++++++++++++++++++++++++++ types/tsconfig.json | 13 +++ types/tslint.json | 7 ++ 16 files changed, 445 insertions(+), 4 deletions(-) create mode 100644 types/ArrayType.d.ts create mode 100644 types/BooleanType.d.ts create mode 100644 types/DateType.d.ts create mode 100644 types/NumberType.d.ts create mode 100644 types/ObjectType.d.ts create mode 100644 types/Schema.d.ts create mode 100644 types/SchemaDeclaration.d.ts create mode 100644 types/StringType.d.ts create mode 100644 types/Type.d.ts create mode 100644 types/index.d.ts create mode 100644 types/test.ts create mode 100644 types/tsconfig.json create mode 100644 types/tslint.json diff --git a/.npmignore b/.npmignore index 8eba6c8..3960a2a 100644 --- a/.npmignore +++ b/.npmignore @@ -1 +1,4 @@ src/ +types/*.json +types/test.ts + diff --git a/CHANGELOG.md b/CHANGELOG.md index a2fc5e0..a69640e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# Next + +- Adding the typescript types declaration in to package + # 1.3.1 - Fixed an issue where `isOneOf` was not valid in `StringType` (#18) diff --git a/package.json b/package.json index 1812aa7..7f1df23 100644 --- a/package.json +++ b/package.json @@ -4,14 +4,16 @@ "description": "Schema for data modeling & validation", "main": "lib/index.js", "module": "es/index.js", + "types": "types/index.d.ts", "scripts": { "lint": "eslint src *.js", "build": "./node_modules/.bin/babel -d lib/ src/", "build-es": "NODE_ENV=esm ./node_modules/.bin/babel -d es/ src/", - "prepublish": "npm run test && npm run build && npm run build-es", + "prepublish": "npm run test && npm run test-types && npm run build && npm run build-es", "tdd": "mocha --watch --compilers js:@babel/register test/*Spec.js ", "test-once": "mocha --compilers js:@babel/register test/*Spec.js ", - "test": "npm run lint && npm run test-once" + "test": "npm run lint && npm run test-once", + "test-types": "dtslint --expectOnly --localTs node_modules/typescript/lib types" }, "repository": { "type": "git", @@ -31,7 +33,8 @@ }, "files": [ "lib", - "es" + "es", + "types" ], "homepage": "https://github.com/rsuite/schema-typed#readme", "devDependencies": { @@ -60,6 +63,7 @@ "babel-eslint": "^9.0.0", "chai": "^3.5.0", "coveralls": "^2.13.1", + "dtslint": "^0.9.9", "eslint": "^3.19.0", "eslint-config-airbnb": "^15.0.1", "eslint-plugin-babel": "^3.2.0", @@ -70,6 +74,7 @@ "eslint-plugin-react": "^7.3.0", "istanbul": "^0.4.5", "mocha": "^2.5.3", - "object-flaser": "^0.1.1" + "object-flaser": "^0.1.1", + "typescript": "^3.6.4" } } diff --git a/types/ArrayType.d.ts b/types/ArrayType.d.ts new file mode 100644 index 0000000..03d9014 --- /dev/null +++ b/types/ArrayType.d.ts @@ -0,0 +1,17 @@ +import { CheckType } from './SchemaDeclaration'; +import { Type } from './Type'; + +export declare class ArrayType extends Type { + constructor(errorMessage?: ErrorMsgType); + rangeLength: (minLength: number, maxLength: number, errorMessage?: ErrorMsgType) => this; + minLength: (minLength: number, errorMessage?: ErrorMsgType) => this; + maxLength: (maxLength: number, errorMessage?: ErrorMsgType) => this; + unrepeatable: (errorMessage?: ErrorMsgType) => this; + of: (type: CheckType, errorMessage?: ErrorMsgType) => this; +} + +declare function getArrayType(errorMessage?: ErrorMsgType): ArrayType; + +type exportType = typeof getArrayType; + +export default exportType; \ No newline at end of file diff --git a/types/BooleanType.d.ts b/types/BooleanType.d.ts new file mode 100644 index 0000000..a3c2771 --- /dev/null +++ b/types/BooleanType.d.ts @@ -0,0 +1,11 @@ +import { Type } from './Type'; + +export declare class BooleanType extends Type { + constructor(errorMessage?: ErrorMsgType); +} + +declare function getBooleanType(errorMessage?: ErrorMsgType): BooleanType; + +type exportType = typeof getBooleanType; + +export default exportType; \ No newline at end of file diff --git a/types/DateType.d.ts b/types/DateType.d.ts new file mode 100644 index 0000000..12ce045 --- /dev/null +++ b/types/DateType.d.ts @@ -0,0 +1,14 @@ +import { Type } from './Type'; + +export declare class DateType extends Type { + constructor(errorMessage?: ErrorMsgType); + range: (min: string | Date, max: string | Date, errorMessage?: ErrorMsgType) => this; + min: (min: string | Date, errorMessage?: ErrorMsgType) => this; + max: (max: string | Date, errorMessage?: ErrorMsgType) => this; +} + +declare function getDateType(errorMessage?: ErrorMsgType): DateType; + +type exportType = typeof getDateType; + +export default exportType; \ No newline at end of file diff --git a/types/NumberType.d.ts b/types/NumberType.d.ts new file mode 100644 index 0000000..933791f --- /dev/null +++ b/types/NumberType.d.ts @@ -0,0 +1,17 @@ +import { Type } from './Type'; + +export declare class NumberType extends Type { + constructor(errorMessage?: ErrorMsgType); + isInteger: (errorMessage?: ErrorMsgType) => this; + pattern: (regexp: RegExp, errorMessage?: ErrorMsgType) => this; + isOneOf: (numLst: number[], errorMessage?: ErrorMsgType) => this; + range: (min: number, max: number, errorMessage?: ErrorMsgType) => this; + min: (min: number, errorMessage?: ErrorMsgType) => this; + max: (max: number, errorMessage?: ErrorMsgType) => this; +} + +declare function getNumberType(errorMessage?: ErrorMsgType): NumberType; + +type exportType = typeof getNumberType; + +export default exportType; \ No newline at end of file diff --git a/types/ObjectType.d.ts b/types/ObjectType.d.ts new file mode 100644 index 0000000..c3b4658 --- /dev/null +++ b/types/ObjectType.d.ts @@ -0,0 +1,13 @@ +import { SchemaDeclaration } from './SchemaDeclaration'; +import { Type } from './Type'; + +export declare class ObjectType extends Type { + constructor(errorMessage?: ErrorMsgType); + shape: (types: SchemaDeclaration) => this; +} + +declare function getObjectType(errorMessage?: ErrorMsgType): ObjectType; + +type exportType = typeof getObjectType; + +export default exportType; \ No newline at end of file diff --git a/types/Schema.d.ts b/types/Schema.d.ts new file mode 100644 index 0000000..db14474 --- /dev/null +++ b/types/Schema.d.ts @@ -0,0 +1,26 @@ +import { CheckType, SchemaDeclaration } from './SchemaDeclaration'; +import { CheckResult } from './Type'; + +type SchemaCheckResult = { + [P in keyof T]: CheckResult +}; + +export declare class Schema { + constructor(schema: SchemaDeclaration); + schema: SchemaDeclaration; + getFieldType: (fieldName: K) => CheckType; + getKeys: () => string[]; + checkForField: (fieldName: K, fieldValue: DataType[K], data?: DataType) => CheckResult; + checkForFieldAsync: (fieldName: K, fieldValue: DataType[K], data?: DataType) => Promise>; + check: (data: DataType) => SchemaCheckResult; + checkAsync: (data: DataType) => Promise>; +} + +declare function SchemaModel(schema: SchemaDeclaration): Schema; + +declare namespace SchemaModel { + const combine: (...models: Array>) => + Schema; +} + +export default SchemaModel; \ No newline at end of file diff --git a/types/SchemaDeclaration.d.ts b/types/SchemaDeclaration.d.ts new file mode 100644 index 0000000..e53cfa6 --- /dev/null +++ b/types/SchemaDeclaration.d.ts @@ -0,0 +1,24 @@ +import { ArrayType } from './ArrayType'; +import { BooleanType } from './BooleanType'; +import { DateType } from './DateType'; +import { NumberType } from './NumberType'; +import { StringType } from './StringType'; +import { ObjectType } from './ObjectType'; + +export type CheckType = + X extends string ? StringType | DateType : + X extends number ? NumberType: + X extends boolean ? BooleanType: + X extends Date ? DateType: + X extends Array ? ArrayType: + X extends object ? ObjectType : + StringType | + NumberType | + BooleanType | + ArrayType | + DateType | + ObjectType; + +export type SchemaDeclaration = { + [P in keyof T]: CheckType; +} \ No newline at end of file diff --git a/types/StringType.d.ts b/types/StringType.d.ts new file mode 100644 index 0000000..eba432f --- /dev/null +++ b/types/StringType.d.ts @@ -0,0 +1,24 @@ +import { Type } from './Type'; + +export declare class StringType extends Type { + constructor(errorMessage?: ErrorMsgType); + containsLetter: (errorMessage?: ErrorMsgType) => this; + containsUppercaseLetter: (errorMessage?: ErrorMsgType) => this; + containsLowercaseLetter: (errorMessage?: ErrorMsgType) => this; + containsLetterOnly: (errorMessage?: ErrorMsgType) => this; + containsNumber: (errorMessage?: ErrorMsgType) => this; + isOneOf: (strArr: string[], errorMessage?: ErrorMsgType) => this; + isEmail: (errorMessage?: ErrorMsgType) => this; + isURL: (errorMessage?: ErrorMsgType) => this; + isHex: (errorMessage?: ErrorMsgType) => this; + pattern: (regexp: RegExp, errorMessage?: ErrorMsgType) => this; + rangeLength: (minLength: number, maxLength: number, errorMessage?: ErrorMsgType) => this; + minLength: (minLength: number, errorMessage?: ErrorMsgType) => this; + maxLength: (maxLength: number, errorMessage?: ErrorMsgType) => this; +} + +declare function getStringType(errorMessage?: ErrorMsgType): StringType; + +type exportType = typeof getStringType; + +export default exportType; \ No newline at end of file diff --git a/types/Type.d.ts b/types/Type.d.ts new file mode 100644 index 0000000..9ddf05b --- /dev/null +++ b/types/Type.d.ts @@ -0,0 +1,17 @@ +interface CheckResult { + hasError: boolean; + errorMessage: ErrorMsgType; +} + +declare class Type { + constructor(name: PropertyKey); + check: (value: ValueType, data: any) => CheckResult; + addRule: ( + onValid: (value: ValueType, data: DataType) => + CheckResult | boolean | void | undefined | Promise | Promise> | Promise, + errorMessage?: ErrorMsgType + ) => this; + isRequired: (errorMessage?: ErrorMsgType) => this; +} + +export { CheckResult, Type }; \ No newline at end of file diff --git a/types/index.d.ts b/types/index.d.ts new file mode 100644 index 0000000..7bc68f2 --- /dev/null +++ b/types/index.d.ts @@ -0,0 +1,49 @@ +import ArrayType, { ArrayType as ArrayCheckType } from './ArrayType'; +import BooleanType, { BooleanType as BooleanCheckType } from './BooleanType'; +import DateType, { DateType as DateCheckType } from './DateType'; +import NumberType, { NumberType as NumberCheckType } from './NumberType'; +import StringType, { StringType as StringCheckType } from './StringType'; +import ObjectType, { ObjectType as ObjectCheckType } from './ObjectType'; +import SchemaModel, { Schema } from './Schema'; +import { SchemaDeclaration } from './SchemaDeclaration'; + +export type CheckType = + ArrayCheckType + | BooleanCheckType + | DateCheckType + | NumberCheckType + | StringCheckType + | ObjectCheckType; + +declare const ArrayType: ArrayType; +declare const BooleanType: BooleanType; +declare const DateType: DateType; +declare const StringType: StringType; +declare const ObjectType: ObjectType; +declare const NumberType: NumberType; + +export { + ArrayType, + BooleanType, + DateType, + StringType, + ObjectType, + NumberType, + SchemaModel, + SchemaDeclaration, + Schema +} + +declare namespace SchemaNs { + const Model: typeof SchemaModel; + const Types: { + StringType: StringType; + NumberType: NumberType; + ArrayType: ArrayType; + DateType: DateType; + ObjectType: ObjectType; + BooleanType: BooleanType; + }; +} + +export default SchemaNs; \ No newline at end of file diff --git a/types/test.ts b/types/test.ts new file mode 100644 index 0000000..d07c0fa --- /dev/null +++ b/types/test.ts @@ -0,0 +1,197 @@ +import { + BooleanType, + NumberType, + StringType, + DateType, + ArrayType, + ObjectType, + Schema, + SchemaModel +} from './index'; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PASSING SCENARIO 1: Should not fail if proper check types are used + +interface PassObj {s: string} +interface Pass {n: number, b: boolean, s: string, d: Date, a: Array, o: PassObj } + +const passSchema = new Schema({ + n: NumberType(), + b: BooleanType(), + s: StringType(), + d: DateType(), + a: ArrayType(), + o: ObjectType(), +}); + +passSchema.check({a: ['a'], b: false, d: new Date(), n: 0, o: {s: ""}, s: ""}); +passSchema.checkAsync({a: ['a'], b: false, d: new Date(), n: 0, o: {s: ""}, s: ""}); +passSchema.checkForField("o", {s : "1"}); +passSchema.checkForFieldAsync("o", {s : "1"}); + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PASSING SCENARIO 2: Should allows combine proper schemas + +SchemaModel.combine<{x: string, y: string}>( + new Schema<{x: string}>({x: StringType()}), + new Schema<{y: string}>({y: StringType()})); + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FAIL SCENARIO 1: Should fail if type check is not matching declared type + +interface F1 {a: string} +new Schema({ + // $ExpectError + a: NumberType() + // TS2322: Type 'NumberType' is not assignable to type 'StringType | DateType'. + // Type 'NumberType' is not assignable to type 'DateType'. + // Types of property 'range' are incompatible. + // Type '(min: number, max: number, errorMessage: string) => NumberType' is not assignable to type '(min: string | Date, max: string | Date, errorMessage: string) => DateType'. + // Types of parameters 'min' and 'min' are incompatible. + // Type 'string | Date' is not assignable to type 'number'. + // Type 'string' is not assignable to type 'number'. +}); + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FAIL SCENARIO 2: Should fail if checks declaration provides check for undeclared property + +interface F2 {a: string} +new Schema({ + // $ExpectError + b: NumberType() + // TS2345: Argument of type '{ b: NumberType; }' is not assignable to parameter of type 'SchemaDeclaration'. + // Object literal may only specify known properties, and 'b' does not exist in type 'SchemaDeclaration'. +}); + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FAIL SCENARIO 3: Should fail if custom rule check will not fallow proper type for value + +interface F3 {a: string} +new Schema({ + // $ExpectError + a: StringType().addRule((v: number) => true) + // TS2345: Argument of type '(v: number) => true' is not assignable to parameter of type '(value: string, data: any) => boolean | void | CheckResult | Promise | Promise | Promise>'. + // Types of parameters 'v' and 'value' are incompatible. + // Type 'string' is not assignable to type 'number'. +}); + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FAIL SCENARIO 4: Should fail if custom rule check will not fallow proper type for data + +interface F4 {a: string} +new Schema({ + // $ExpectError + a: StringType().addRule((v: string, d: number) => true) + // TS2345: Argument of type '(v: string, d: number) => true' is not assignable to parameter of type '(value: string, data: F4) => boolean | void | CheckResult | Promise | Promise | Promise>'. + // Types of parameters 'd' and 'data' are incompatible. + // Type 'F4' is not assignable to type 'number'. +}); + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FAIL SCENARIO 5: Should fail if check and checkAsync function is called with not matching type + +interface F5 {a: string} +const schemaF5 = new Schema({ + a: StringType() +}); + +// $ExpectError +schemaF5.check({ c: 12}); +// TS2345: Argument of type '{ c: number; }' is not assignable to parameter of type 'F5'. +// Object literal may only specify known properties, and 'c' does not exist in type 'F5'. + +// $ExpectError +schemaF5.checkAsync({ c: 12}); +// TS2345: Argument of type '{ c: number; }' is not assignable to parameter of type 'F5'. +// Object literal may only specify known properties, and 'c' does not exist in type 'F5'. + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FAIL SCENARIO 6: Should fail if checkForField function is called with non existing property name + +interface F6 {a: string} +const schemaF6 = new Schema({ + a: StringType() +}); + +// $ExpectError +schemaF6.checkForField('c', 'a'); +// TS2345: Argument of type '"c"' is not assignable to parameter of type '"a"'. + +// $ExpectError +schemaF6.checkForFieldAsync('c', 'a'); +// TS2345: Argument of type '"c"' is not assignable to parameter of type '"a"'. + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FAIL SCENARIO 7: Should fail if check and checkAsync function is called with not matching type, when type is inferred + +const schemaF7 = new Schema({ + a: StringType() +}); + +// $ExpectError +schemaF7.check({ c: 12}); +// TS2345: Argument of type '{ c: number; }' is not assignable to parameter of type '{ a: unknown; }'. +// Object literal may only specify known properties, and 'c' does not exist in type '{ a: unknown; }'. + +// $ExpectError +schemaF7.checkAsync({ c: 12}); +// TS2345: Argument of type '{ c: number; }' is not assignable to parameter of type '{ a: unknown; }'. +// Object literal may only specify known properties, and 'c' does not exist in type '{ a: unknown; }'. + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FAIL SCENARIO 8: Should fail if checkForField function is called with non existing property name, when type is inferred + +const schemaF8 = new Schema({ + a: StringType() +}); + +// $ExpectError +schemaF8.checkForField('c', 'a'); +// TS2345: Argument of type '"c"' is not assignable to parameter of type '"a"'. + +// $ExpectError +schemaF8.checkForFieldAsync('c', 'a'); +// TS2345: Argument of type '"c"' is not assignable to parameter of type '"a"'. + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FAIL SCENARIO 9: Should fail if ObjectType will get not matched shape + +interface F9 {a: string} +ObjectType().shape({ + // $ExpectError + a: NumberType() + // TS2322: Type 'NumberType' is not assignable to type 'StringType | DateType'. + // Type 'NumberType' is not assignable to type 'DateType'. + // Types of property 'range' are incompatible. + // Type '(min: number, max: number, errorMessage: string) => NumberType' is not assignable to type '(min: string | Date, max: string | Date, errorMessage: string) => DateType'. + // Types of parameters 'min' and 'min' are incompatible. + // Type 'string | Date' is not assignable to type 'number'. + // Type 'string' is not assignable to type 'number'. +}); +ObjectType().shape({ + // $ExpectError + b: NumberType() + // TS2345: Argument of type '{ b: NumberType; }' is not assignable to parameter of type 'SchemaDeclaration'. + // Object literal may only specify known properties, and 'b' does not exist in type 'SchemaDeclaration'. +}); + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FAIL SCENARIO 10: Should fail if ArrayType will get not matched shape + +interface F10 {a: string} +// $ExpectError +ArrayType().of(StringType()); +// TS2345: Argument of type 'StringType' is not assignable to parameter of type 'ObjectType'. +// Property 'shape' is missing in type 'StringType' but required in type 'ObjectType'. + diff --git a/types/tsconfig.json b/types/tsconfig.json new file mode 100644 index 0000000..507d4a4 --- /dev/null +++ b/types/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": ["es6"], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noEmit": true, + "baseUrl": ".", + "paths": { "schema-typed": ["."] } + } +} \ No newline at end of file diff --git a/types/tslint.json b/types/tslint.json new file mode 100644 index 0000000..e799385 --- /dev/null +++ b/types/tslint.json @@ -0,0 +1,7 @@ +{ + "extends": "dtslint/dtslint.json", // Or "dtslint/dt.json" if on DefinitelyTyped + "rules": { + "semicolon": false, + "indent": [true, "tabs"] + } +} \ No newline at end of file From 192fc909fa341b8dfd738167427d89d7b96d8e8b Mon Sep 17 00:00:00 2001 From: majo44 Date: Mon, 28 Oct 2019 13:46:25 +0100 Subject: [PATCH 2/7] Added tests. --- types/SchemaDeclaration.d.ts | 2 +- types/test.ts | 44 +++++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/types/SchemaDeclaration.d.ts b/types/SchemaDeclaration.d.ts index e53cfa6..4f8bcfe 100644 --- a/types/SchemaDeclaration.d.ts +++ b/types/SchemaDeclaration.d.ts @@ -6,7 +6,7 @@ import { StringType } from './StringType'; import { ObjectType } from './ObjectType'; export type CheckType = - X extends string ? StringType | DateType : + X extends string ? StringType | DateType | NumberType: X extends number ? NumberType: X extends boolean ? BooleanType: X extends Date ? DateType: diff --git a/types/test.ts b/types/test.ts index d07c0fa..a33b56a 100644 --- a/types/test.ts +++ b/types/test.ts @@ -16,12 +16,12 @@ interface PassObj {s: string} interface Pass {n: number, b: boolean, s: string, d: Date, a: Array, o: PassObj } const passSchema = new Schema({ - n: NumberType(), - b: BooleanType(), - s: StringType(), - d: DateType(), - a: ArrayType(), - o: ObjectType(), + n: NumberType(), + b: BooleanType(), + s: StringType(), + d: DateType(), + a: ArrayType(), + o: ObjectType(), }); passSchema.check({a: ['a'], b: false, d: new Date(), n: 0, o: {s: ""}, s: ""}); @@ -38,6 +38,38 @@ SchemaModel.combine<{x: string, y: string}>( new Schema<{y: string}>({y: StringType()})); +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PASSING SCENARIO 3: Should allows adding custom rules which have proper types on callback + +SchemaModel<{password1: string, password2: string}>({ + password1: StringType(), + password2: StringType().addRule((value, data) => value.toLowerCase() === data.password1.toLowerCase()) +}); + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PASSING SCENARIO 4: Should allows to use custom error message type +SchemaModel<{a: string}, number>({ + a: StringType<{a: string}, number>().addRule(() => ({ + hasError: true, + errorMessage: 500, + })) +}); + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PASSING SCENARIO 5: Should allows to use NumberType on string field +SchemaModel<{a: string}>({ + a: NumberType<{a: string}>() +}); + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PASSING SCENARIO 6: Should allows to use DataType on string field +SchemaModel<{a: string}>({ + a: DateType<{a: string}>() +}); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // FAIL SCENARIO 1: Should fail if type check is not matching declared type From 9945a0e177f4f0e3663671d797b4a8bce8f02d38 Mon Sep 17 00:00:00 2001 From: majo44 Date: Mon, 28 Oct 2019 13:51:50 +0100 Subject: [PATCH 3/7] Added tests. --- types/test.ts | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/types/test.ts b/types/test.ts index a33b56a..0539dec 100644 --- a/types/test.ts +++ b/types/test.ts @@ -77,14 +77,9 @@ SchemaModel<{a: string}>({ interface F1 {a: string} new Schema({ // $ExpectError - a: NumberType() - // TS2322: Type 'NumberType' is not assignable to type 'StringType | DateType'. - // Type 'NumberType' is not assignable to type 'DateType'. - // Types of property 'range' are incompatible. - // Type '(min: number, max: number, errorMessage: string) => NumberType' is not assignable to type '(min: string | Date, max: string | Date, errorMessage: string) => DateType'. - // Types of parameters 'min' and 'min' are incompatible. - // Type 'string | Date' is not assignable to type 'number'. - // Type 'string' is not assignable to type 'number'. + a: BooleanType() + // TS2322: Type 'BooleanType' is not assignable to type 'StringType | DateType | NumberType'. + // Type 'BooleanType' is missing the following properties from type 'NumberType': isInteger, pattern, isOneOf, range, and 2 more. }); @@ -201,14 +196,9 @@ schemaF8.checkForFieldAsync('c', 'a'); interface F9 {a: string} ObjectType().shape({ // $ExpectError - a: NumberType() - // TS2322: Type 'NumberType' is not assignable to type 'StringType | DateType'. - // Type 'NumberType' is not assignable to type 'DateType'. - // Types of property 'range' are incompatible. - // Type '(min: number, max: number, errorMessage: string) => NumberType' is not assignable to type '(min: string | Date, max: string | Date, errorMessage: string) => DateType'. - // Types of parameters 'min' and 'min' are incompatible. - // Type 'string | Date' is not assignable to type 'number'. - // Type 'string' is not assignable to type 'number'. + a: BooleanType() + // TS2322: Type 'BooleanType' is not assignable to type 'StringType | DateType | NumberType'. + // Type 'BooleanType' is missing the following properties from type 'NumberType': isInteger, pattern, isOneOf, range, and 2 more. }); ObjectType().shape({ // $ExpectError From 721de439f350ae642fb4ec55a90db9301560f230 Mon Sep 17 00:00:00 2001 From: majo44 Date: Mon, 4 Nov 2019 10:35:20 +0100 Subject: [PATCH 4/7] Small fix of declaration --- types/SchemaDeclaration.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/SchemaDeclaration.d.ts b/types/SchemaDeclaration.d.ts index 4f8bcfe..afac73b 100644 --- a/types/SchemaDeclaration.d.ts +++ b/types/SchemaDeclaration.d.ts @@ -5,7 +5,7 @@ import { NumberType } from './NumberType'; import { StringType } from './StringType'; import { ObjectType } from './ObjectType'; -export type CheckType = +export type CheckType = X extends string ? StringType | DateType | NumberType: X extends number ? NumberType: X extends boolean ? BooleanType: @@ -19,6 +19,6 @@ export type CheckType = DateType | ObjectType; -export type SchemaDeclaration = { +export type SchemaDeclaration = { [P in keyof T]: CheckType; } \ No newline at end of file From 4f9f754778bd6d8b657f58c018fe369d801a3c52 Mon Sep 17 00:00:00 2001 From: majo44 Date: Tue, 5 Nov 2019 13:17:19 +0100 Subject: [PATCH 5/7] Allows reflection. --- types/ArrayType.d.ts | 1 + types/BooleanType.d.ts | 1 + types/DateType.d.ts | 1 + types/NumberType.d.ts | 1 + types/ObjectType.d.ts | 1 + types/StringType.d.ts | 1 + types/Type.d.ts | 3 ++- 7 files changed, 8 insertions(+), 1 deletion(-) diff --git a/types/ArrayType.d.ts b/types/ArrayType.d.ts index 03d9014..b427839 100644 --- a/types/ArrayType.d.ts +++ b/types/ArrayType.d.ts @@ -2,6 +2,7 @@ import { CheckType } from './SchemaDeclaration'; import { Type } from './Type'; export declare class ArrayType extends Type { + name: 'array'; constructor(errorMessage?: ErrorMsgType); rangeLength: (minLength: number, maxLength: number, errorMessage?: ErrorMsgType) => this; minLength: (minLength: number, errorMessage?: ErrorMsgType) => this; diff --git a/types/BooleanType.d.ts b/types/BooleanType.d.ts index a3c2771..07d64d4 100644 --- a/types/BooleanType.d.ts +++ b/types/BooleanType.d.ts @@ -1,6 +1,7 @@ import { Type } from './Type'; export declare class BooleanType extends Type { + name: 'boolean'; constructor(errorMessage?: ErrorMsgType); } diff --git a/types/DateType.d.ts b/types/DateType.d.ts index 12ce045..bb116c5 100644 --- a/types/DateType.d.ts +++ b/types/DateType.d.ts @@ -1,6 +1,7 @@ import { Type } from './Type'; export declare class DateType extends Type { + name: 'date'; constructor(errorMessage?: ErrorMsgType); range: (min: string | Date, max: string | Date, errorMessage?: ErrorMsgType) => this; min: (min: string | Date, errorMessage?: ErrorMsgType) => this; diff --git a/types/NumberType.d.ts b/types/NumberType.d.ts index 933791f..7450e0a 100644 --- a/types/NumberType.d.ts +++ b/types/NumberType.d.ts @@ -1,6 +1,7 @@ import { Type } from './Type'; export declare class NumberType extends Type { + name: 'number'; constructor(errorMessage?: ErrorMsgType); isInteger: (errorMessage?: ErrorMsgType) => this; pattern: (regexp: RegExp, errorMessage?: ErrorMsgType) => this; diff --git a/types/ObjectType.d.ts b/types/ObjectType.d.ts index c3b4658..d0e87cc 100644 --- a/types/ObjectType.d.ts +++ b/types/ObjectType.d.ts @@ -2,6 +2,7 @@ import { SchemaDeclaration } from './SchemaDeclaration'; import { Type } from './Type'; export declare class ObjectType extends Type { + name: 'object'; constructor(errorMessage?: ErrorMsgType); shape: (types: SchemaDeclaration) => this; } diff --git a/types/StringType.d.ts b/types/StringType.d.ts index eba432f..d37410c 100644 --- a/types/StringType.d.ts +++ b/types/StringType.d.ts @@ -1,6 +1,7 @@ import { Type } from './Type'; export declare class StringType extends Type { + name: 'string'; constructor(errorMessage?: ErrorMsgType); containsLetter: (errorMessage?: ErrorMsgType) => this; containsUppercaseLetter: (errorMessage?: ErrorMsgType) => this; diff --git a/types/Type.d.ts b/types/Type.d.ts index 9ddf05b..6e0d561 100644 --- a/types/Type.d.ts +++ b/types/Type.d.ts @@ -4,7 +4,8 @@ interface CheckResult { } declare class Type { - constructor(name: PropertyKey); + name: string; + constructor(name: string); check: (value: ValueType, data: any) => CheckResult; addRule: ( onValid: (value: ValueType, data: DataType) => From 516a3b19b83b44a7217b14a7c85d0ae154787786 Mon Sep 17 00:00:00 2001 From: majo44 Date: Tue, 5 Nov 2019 13:24:14 +0100 Subject: [PATCH 6/7] Allows reflection of array and object types. --- src/ArrayType.js | 1 + src/ObjectType.js | 1 + types/ArrayType.d.ts | 1 + types/ObjectType.d.ts | 1 + 4 files changed, 4 insertions(+) diff --git a/src/ArrayType.js b/src/ArrayType.js index c55fd64..37a237d 100644 --- a/src/ArrayType.js +++ b/src/ArrayType.js @@ -48,6 +48,7 @@ class ArrayType extends Type { * ) */ of(type, errorMessage) { + this.ofType = type; super.pushRule(items => { let valids = items.map(value => type.check(value)); let errors = valids.filter(item => item.hasError) || []; diff --git a/src/ObjectType.js b/src/ObjectType.js index 206634a..01458e0 100644 --- a/src/ObjectType.js +++ b/src/ObjectType.js @@ -18,6 +18,7 @@ class ObjectType extends Type { * }) */ shape(types) { + this.shapeType = types; super.pushRule(values => { let valids = Object.entries(types).map(item => { let key = item[0]; diff --git a/types/ArrayType.d.ts b/types/ArrayType.d.ts index b427839..da3709a 100644 --- a/types/ArrayType.d.ts +++ b/types/ArrayType.d.ts @@ -3,6 +3,7 @@ import { Type } from './Type'; export declare class ArrayType extends Type { name: 'array'; + readonly ofType: CheckType; constructor(errorMessage?: ErrorMsgType); rangeLength: (minLength: number, maxLength: number, errorMessage?: ErrorMsgType) => this; minLength: (minLength: number, errorMessage?: ErrorMsgType) => this; diff --git a/types/ObjectType.d.ts b/types/ObjectType.d.ts index d0e87cc..4730b36 100644 --- a/types/ObjectType.d.ts +++ b/types/ObjectType.d.ts @@ -3,6 +3,7 @@ import { Type } from './Type'; export declare class ObjectType extends Type { name: 'object'; + readonly shapeType: SchemaDeclaration; constructor(errorMessage?: ErrorMsgType); shape: (types: SchemaDeclaration) => this; } From fe1c3c2f7ef9b6c5587a8b7bf491ca046a35d603 Mon Sep 17 00:00:00 2001 From: majo44 Date: Tue, 5 Nov 2019 18:12:20 +0100 Subject: [PATCH 7/7] MArk the type name as readonly. --- types/ArrayType.d.ts | 2 +- types/BooleanType.d.ts | 2 +- types/DateType.d.ts | 2 +- types/NumberType.d.ts | 2 +- types/ObjectType.d.ts | 2 +- types/StringType.d.ts | 2 +- types/Type.d.ts | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/types/ArrayType.d.ts b/types/ArrayType.d.ts index b427839..a310475 100644 --- a/types/ArrayType.d.ts +++ b/types/ArrayType.d.ts @@ -2,7 +2,7 @@ import { CheckType } from './SchemaDeclaration'; import { Type } from './Type'; export declare class ArrayType extends Type { - name: 'array'; + readonly name: 'array'; constructor(errorMessage?: ErrorMsgType); rangeLength: (minLength: number, maxLength: number, errorMessage?: ErrorMsgType) => this; minLength: (minLength: number, errorMessage?: ErrorMsgType) => this; diff --git a/types/BooleanType.d.ts b/types/BooleanType.d.ts index 07d64d4..c98e758 100644 --- a/types/BooleanType.d.ts +++ b/types/BooleanType.d.ts @@ -1,7 +1,7 @@ import { Type } from './Type'; export declare class BooleanType extends Type { - name: 'boolean'; + readonly name: 'boolean'; constructor(errorMessage?: ErrorMsgType); } diff --git a/types/DateType.d.ts b/types/DateType.d.ts index bb116c5..c4ee0e7 100644 --- a/types/DateType.d.ts +++ b/types/DateType.d.ts @@ -1,7 +1,7 @@ import { Type } from './Type'; export declare class DateType extends Type { - name: 'date'; + readonly name: 'date'; constructor(errorMessage?: ErrorMsgType); range: (min: string | Date, max: string | Date, errorMessage?: ErrorMsgType) => this; min: (min: string | Date, errorMessage?: ErrorMsgType) => this; diff --git a/types/NumberType.d.ts b/types/NumberType.d.ts index 7450e0a..20e872b 100644 --- a/types/NumberType.d.ts +++ b/types/NumberType.d.ts @@ -1,7 +1,7 @@ import { Type } from './Type'; export declare class NumberType extends Type { - name: 'number'; + readonly name: 'number'; constructor(errorMessage?: ErrorMsgType); isInteger: (errorMessage?: ErrorMsgType) => this; pattern: (regexp: RegExp, errorMessage?: ErrorMsgType) => this; diff --git a/types/ObjectType.d.ts b/types/ObjectType.d.ts index d0e87cc..c271994 100644 --- a/types/ObjectType.d.ts +++ b/types/ObjectType.d.ts @@ -2,7 +2,7 @@ import { SchemaDeclaration } from './SchemaDeclaration'; import { Type } from './Type'; export declare class ObjectType extends Type { - name: 'object'; + readonly name: 'object'; constructor(errorMessage?: ErrorMsgType); shape: (types: SchemaDeclaration) => this; } diff --git a/types/StringType.d.ts b/types/StringType.d.ts index d37410c..33ed303 100644 --- a/types/StringType.d.ts +++ b/types/StringType.d.ts @@ -1,7 +1,7 @@ import { Type } from './Type'; export declare class StringType extends Type { - name: 'string'; + readonly name: 'string'; constructor(errorMessage?: ErrorMsgType); containsLetter: (errorMessage?: ErrorMsgType) => this; containsUppercaseLetter: (errorMessage?: ErrorMsgType) => this; diff --git a/types/Type.d.ts b/types/Type.d.ts index 6e0d561..842fa0b 100644 --- a/types/Type.d.ts +++ b/types/Type.d.ts @@ -4,7 +4,7 @@ interface CheckResult { } declare class Type { - name: string; + readonly name: string; constructor(name: string); check: (value: ValueType, data: any) => CheckResult; addRule: (