From d9195c5f95448ce56a11a82541ced7243c3de108 Mon Sep 17 00:00:00 2001 From: thetek Date: Thu, 21 Mar 2024 19:45:27 +0100 Subject: [PATCH] init: typia-proof-of-concept --- typia-proof-of-concept/.gitignore | 3 + typia-proof-of-concept/README.md | 11 +++ typia-proof-of-concept/package.json | 18 +++++ typia-proof-of-concept/src/index.ts | 110 +++++++++++++++++++++++++++ typia-proof-of-concept/tsconfig.json | 21 +++++ 5 files changed, 163 insertions(+) create mode 100644 typia-proof-of-concept/.gitignore create mode 100644 typia-proof-of-concept/README.md create mode 100644 typia-proof-of-concept/package.json create mode 100644 typia-proof-of-concept/src/index.ts create mode 100644 typia-proof-of-concept/tsconfig.json diff --git a/typia-proof-of-concept/.gitignore b/typia-proof-of-concept/.gitignore new file mode 100644 index 0000000..5cdf045 --- /dev/null +++ b/typia-proof-of-concept/.gitignore @@ -0,0 +1,3 @@ +/dist +/node_modules +/yarn.lock diff --git a/typia-proof-of-concept/README.md b/typia-proof-of-concept/README.md new file mode 100644 index 0000000..5f75ad8 --- /dev/null +++ b/typia-proof-of-concept/README.md @@ -0,0 +1,11 @@ +# Typia Proof of Concept + +## Running + +```sh +yarn run demo +``` + +## Resources + +- Typia: [Repository](https://github.com/samchon/typia), [Documentation](https://typia.io/docs/) diff --git a/typia-proof-of-concept/package.json b/typia-proof-of-concept/package.json new file mode 100644 index 0000000..a49deac --- /dev/null +++ b/typia-proof-of-concept/package.json @@ -0,0 +1,18 @@ +{ + "name": "typia-proof-of-concept", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "devDependencies": { + "ts-node": "^10.9.2", + "ts-patch": "^3.1.2", + "typescript": "5.4.2" + }, + "dependencies": { + "typia": "^5.5.7" + }, + "scripts": { + "prepare": "ts-patch install && typia patch", + "demo": "tsc && node dist/index.js" + } +} diff --git a/typia-proof-of-concept/src/index.ts b/typia-proof-of-concept/src/index.ts new file mode 100644 index 0000000..0091343 --- /dev/null +++ b/typia-proof-of-concept/src/index.ts @@ -0,0 +1,110 @@ +import typia, { tags } from "typia"; + + + +/* type definitions */ + +type User = { + username: string & tags.MinLength<4> & tags.MaxLength<16>, // string with minimum and maximum length + birthdate: DateString, // custom type that also has constrains added to it + pets: Pet[] & tags.MinItems<1>, // bounds for number of items in list + favouriteTvSeries?: string, // optional properties +}; + +// custom type +type DateString = string & tags.Format<"date">; + +type Cat = { + animalType: "cat", // `animalType` can only be "cat", "dog" or "bird" + numberOfLivesLeft: number & tags.Type<"uint32"> & tags.Maximum<9>, // integer and maximum value constrains +}; + +type Dog = { + animalType: "dog", + favouriteDogFoodBrand?: string, +}; + +type Bird = { + animalType: "bird", +}; + +type Pet = (Cat | Dog | Bird) & { + name: string, +}; + +// other possibilities: +// - other built-in formats: email, uuid, url, json pointers, ... +// - check string for regex pattern +// - completely custom constraints for tags + + + +/* json samples */ + +// valid +const SAMPLE_1 = `{ + "username": "meyer.sepp", + "birthdate": "1983-03-28", + "pets": [ + { "animalType": "cat", "name": "Kittykatty", "numberOfLivesLeft": 5 }, + { "animalType": "dog", "name": "Olaf", "favouriteDogFoodBrand": "DogGo!" }, + { "animalType": "bird", "name": "Lori" }, + { "animalType": "bird", "name": "Flori" } + ], + "favouriteTvSeries": "The Office" +}`; + +// missing property `birthdate` +const SAMPLE_2 = `{ + "username": "foofa", + "pets": [ + { "animalType": "dog", "name": "Ludwig" } + ] +}`; + +// additional property `id` +const SAMPLE_3 = `{ + "id": 42, + "username": "IcyToothPaste", + "birthdate": "2001-08-08", + "pets": [ + { "animalType": "cat", "name": "Susi", "numberOfLivesLeft": 9 }, + { "animalType": "cat", "name": "Lolo", "numberOfLivesLeft": 8 } + ] +}`; + +// incorrect values: too short username, malformatted date, invalid +// `animalType`, incorrect value for `numberOfLivesLeft` +const SAMPLE_4 = `{ + "username": "qux", + "birthdate": "04/32/1947", + "pets": [ + { "animalType": "turtle", "name": "Schildi" }, + { "animalType": "cat", "name": "Felix", "numberOfLivesLeft": 11 } + ] +}`; + +const SAMPLES = [SAMPLE_1, SAMPLE_2, SAMPLE_3, SAMPLE_4]; + + + +/* validation */ + +const validator = typia.createValidateEquals(); + +for (const idx in SAMPLES) { + const json = SAMPLES[idx]; + const parsed = JSON.parse(json); + const validationResult = validator(parsed); + + if (validationResult.success) { + console.log(`sample ${idx + 1}: success`); + // here, we can retrieve the actual `User` object with: + // const user = validationResult.data; + } else { + console.log(`sample ${idx + 1}: failure`); + for (const error of validationResult.errors) { + console.log(` - ${error.path}, expected ${error.expected}, found value ${error.value}`); + } + } +} diff --git a/typia-proof-of-concept/tsconfig.json b/typia-proof-of-concept/tsconfig.json new file mode 100644 index 0000000..8b5f2b6 --- /dev/null +++ b/typia-proof-of-concept/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "rootDir": "src/", + "outDir": "dist/", + "plugins": [ + { + "transform": "typia/lib/transform" + } + ], + "strictNullChecks": true + }, + "include": [ + "src/" + ] +} \ No newline at end of file