diff --git a/.github/workflows/publish-to-npm.yaml b/.github/workflows/publish-to-npm.yaml new file mode 100644 index 0000000..e69de29 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e69de29 diff --git a/FUNDING.yaml b/FUNDING.yaml new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md index b877ec5..1ece3fc 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,383 @@ -# **TypeScriptAssets** - enhance your `TypeScript` -### Powerful library for `TypeScript`, that provides better typing support with additional *utility generics* and *typing predicates* +# **TypeScriptAssets** - enhance your *TypeScript* +### Powerful library for *TypeScript*, that provides better typing support with additional *utility generics* and *typing predicates* + +This library was made for advanced *TypeScript* users, if you do not now what is *type guard*, *assert* keyword, *utility generics*, then you should read blogs below and then come back to this library ++ [Utility types official docs]() ++ [Asserters guide](https://blog.logrocket.com/assertion-functions-typescript/) ++ [Type guards guide](https://blog.logrocket.com/how-to-use-type-guards-typescript/) +--- +### What **TypeScriptAssets** can do? -## `TypeScriptAssets` *be like:* Additional **utility** types + New utility types will make your type aggregation more comfortable + You don't need to provide your own utility types in your project, just import this library + Full type safety Type **predicators generation** -+ Now you don't need to write asserters and guards by your own, just use `generatePredicatos` function, and it will generate both **guard** and **asserter** for your type based on given params ++ Now you don't need to write asserters and guards by your own, just use `generatePredicates` function, and it will generate both **guard** and **asserter** for your type based on given params + You can generate **guard** or **asserter** separately + Full type safety, just if like you writed the **guard** ++ *Conditional* (custom) **type guard** generation by validation function + ***100%* Test coverage** **Property aggregation** functions -+ Exclude and remove properties with *type safety* ++ Pick and remove properties with *type safety* + ***100%* Test coverage** -Examples of usage you can find here +### Documantation map: +> [**Utility types**](#utility-generic-types) +>> [`DeepOptional`](#deepoptionalt) - makes all nested properties optional +>> +>> [`DeepRequired`](#deeprequiredt) - makes all nested properties required +>> +>> [`ValueOf`](#valueoft) - extracts union type of values from object +>> +>> [`FromArray`](#fromarrayt) - extracts union type from array +>> +>> [`ExcludeNullable`](#excludenullablet) - excludes all nested *nullable* types from unions in object +>> +>> [`ExcludeActual`](#excludeactualt) - excludes all nested *non-nullable* types from unions in object +>> +>> [`ActualReturnType`](#actualreturntypet) - return type of function without *Promise* generic and *Awaited* keyword +>> +> [**Predicates**](#predicates) +>> [`generateGuard`](#generateguard) - generates type guard function by provided type checking property and it's *primitive type*, for ex. `generateGuard(user, "name", "string")` +>> +>> [`generateConditionalGuard`](#generateconditionalguard) - generates type guard function by provided validation callback +>> +>> [`generateAsserter`](#generateasserter) - generates type asserter function by provided validation callback +>> +>> [`generatePredicates`](#generatepredicates) - generates both type asserter and guard. Has 2 overloads for generating by property primitive and by validation callback +>> +> [**Property aggregators**](#property-aggergators) +>> [`excludeProperties`](#excludeproperties) - excludes provided properties with type safety +>> +>> [`pickProperties`](#pickproperties) - picks provided properties with type safety +--- + +## Utility generic types: + +### `DeepOptional` + +Making all nested fields optional. Returns `T` type if it is not extending `object` +```TypeScript +type User = { + name: string + age: number + cc: { + code: string + cvv: number + } +} + +/* +* name?: string +* age?: number +* cc?: { +* code?: string +* cvv?: number +* } +*/ +type OptionalUser = DeepOptional +``` +--- +### `DeepRequired` +Making all nested fields required. Returns `T` type if it is not extending `object` +```TypeScript +type User = { + name: string + age: number + cc?: { + code?: string + cvv: number + } +} + +/* +* ... +* cc: { +* code: string +* cvv: number +* } +*/ +type RequiredlUser = DeepRequired +``` +--- +### `ValueOf` +Exports union of all possible values (works also with arrays) +```TypeScript +// type A = string +type A = ValueOf + +// type B = string | number +type B = ValueOf<{ "1": "1", "2": 2 }> +``` +--- + +### `FromArray` + +Exports value specifically from array. Returns `T` if it is not array +```TypeScript +// type A = string +type A = FromArray +``` +--- + +### `ExcludeNullable` + +Excludes all nullable unions in nested fields + +```TypeScript +/* a: { +* b: string; +* c: string; +* }; +* x: number; +*/ +type A = ExcludeNullable< + { + a: { + b: string |null | void + c: string + } + x: number undefined + } +> +``` + +--- + +### `ExcludeActual` + +Excludes all primitive types from union type in nested properties +```TypeScript +/* +* { +* a: { +* b: void | null; +* c: never; +* }; +* x: undefined; +* } +*/ +type A = ExcludeActual< + { + a: { + b: string | null | void + c: string + } + x: number | undefined + } +> +``` +--- +### `ActualReturnType` + +Works like `ReturnType` but automatically resolves promises types and excludes nullable values +```TypeScript +function f (): Promise +// A = string +type A = ActualReturnType +``` +--- + +## Predicates: + + ++ Type guards and asserters works better with *branded types*, for more information about branded types you can check out [this](https://www.youtube.com/watch?v=rpw59rajUSI) video + +### `isSameType` + +Takes *1* to *n* arguments, returns *true* if arguments are same type, *false* if not +```TypeScript +// true +const foo = isSameType("a", "b", "") + +// false +const bar = isSameType("a", 1) +``` +--- + +### `generateGuard` + +Generates `type guard` by *property and its primitive type* (basic type guard). Uses for +```TypeScript +type User = { + name: string + age: number + cc: { + code: string + cvv: number + } +} + +const isUser = generateGuard( + "name", "string" +) +// true +isUser({ + name: "Jason", + age: 19, + cc: { + code: "1234 5678 9101 1121", + cvv: 890 + } +}) +``` --- +### `generateConditionalGuard` + +Generates `type guard` functions that guards *by the callback function provided in argument* +```TypeScript +type User = { + name: string + age: number + cc: { + code: string + cvv: number + } +} + +const isUser = generateConditionalGuard( + (entity: unknown) => (entity as User).cc.code.startsWith("1") +) + +// true +isUser({ + name: "Jason", + age: 19, + cc: { + code: "1234 5678 9101 1121", + cvv: 890 + } +}) + +``` + +--- +### `generateAsserter` + +Generates `type asserter`, that throws error if provided object *does not follow provided conditions* (opposite of `type guard`). `isValid` callback should be like in `generateConditionalGuard` function argument +```TypeScript +type User = { + name: string + age: number + cc: { + code: string + cvv: number + } +} + +const assertUser = generateAsserter( + (source: unknown) => (source as User).сс.code.startsWith("34"), + "Your cc code does not starts with 34" +) + +// throw `Error("Your cc code does not starts with 34")` +assertUser({ + name: "Jason", + age: 19, + cc: { + code: "1234 5678 9101 1121", + cvv: 890 + } +}) +``` + +--- + +### `generatePredicates` +Generates both *asserter* and *guard* for promoted type. Has 2 overloads. First generates predicates with provided *validator callback*, second generates predicates via provided property and its primitive type. Both overloads requires *error message* at first argument +```TypeScript +type User = { + name: string + age: number + cc: { + code: string + cvv: number + } +} + +const predicates: Predicates = generatePredicates( + "User is not 18 yo", + (source: unknown) => {return (source as User).age > 18} +) + + +const user = { + name: "Pedro", + age: 17, + cc: { + code: "1231 2312 3132", + cvv: 123 + } +} + +// throws 'Error("User is not 18 yo")' +predicates.assert(user) + +// true +predicates.guard(user) + +``` + +--- + + +## Property aggergators + ++ This is the only feature in this library that may work with the *JavaScript* + +### `excludeProperties` + +Excludes properties from given object. Mutates original object and returns mutated value. Return value will be type safe as with `Omit` + +```TypeScript +const user: User = { + name: "Pedro", + age: 17, + cc: { + code: "1231 2312 3132", + cvv: 123 + } +} +/* +* { +* name: "Pedro", +* age: 17, +* } +*/ +const userWithoutCC: Omit = excludeProperties(user) +``` +--- + +### `pickProperties` + +Opposite of `excludeProperties`, picks properties from original objects. Mutates original object and returns mutated value. Return value will be type safe as with `Pick` + +```TypeScript + +const user: User = { + name: "Pedro", + age: 17, + cc: { + code: "1231 2312 3132", + cvv: 123 + } +} +/* +* { +* name: "Pedro", +* age: 17, +* } +*/ +const userWithoutCC: Pick = pickProperties(user, "age", "name") + + +``` +--- +If you have ideas for enhanching TypeScript with assets similar to those or upgrading current functional, contact me by email or make pull request to this repo. If you are adding new assets and tests running on GitHub Actions are not completing, your PR will be never approved. +Made and documented by [**LCcodder**](https://github.com/LCcodder) \ No newline at end of file diff --git a/scripts/remove_js_files.py b/scripts/remove_js_files.py new file mode 100644 index 0000000..e69de29 diff --git a/src/functions/predicatesAndTyping.ts b/src/functions/predicatesAndTyping.ts index 7f80708..c5f88eb 100644 --- a/src/functions/predicatesAndTyping.ts +++ b/src/functions/predicatesAndTyping.ts @@ -17,7 +17,7 @@ export const isSameType = (...args: unknown[]): boolean => { * @param callback Condition callback function * @returns `Arrow function`, which returns `checkingVariable` is `T` *(boolean)* */ -export function generateConditionalTypeGuard(callback: (entity: T) => boolean): +export function generateConditionalGuard(callback: (entity: T) => boolean): (checkingVariable: unknown) => checkingVariable is T { return (checkingVariable: unknown): checkingVariable is T => { return callback(checkingVariable as T); @@ -29,25 +29,23 @@ export function generateConditionalTypeGuard(callback: (entity: T) => boolean * * @description Function generator for *type guarding* * @param prop Property to check *(must be string or symbol)* - * @param propType This property `type` alias primitive in string + * @param propPrimitive This property `type` alias primitive in string * @returns `Arrow function`, which returns `checkingVariable` is `T` *(boolean)* */ -export function generateTypeGuard(prop: keyof T, propPrimitive: string | symbol): +export function generateGuard(prop: keyof T, propPrimitive: string | symbol): (checkingVariable: unknown) => checkingVariable is T { return (checkingVariable: unknown): checkingVariable is T => { return typeof (checkingVariable as Required)[prop as keyof T] === propPrimitive; } } - /** * - * @description Function generator for *type guarding* - * @param prop Property to check *(must be string or symbol)* - * @param propType This property `type` alias primitive in string - * @returns `Arrow function`, which returns `checkingVariable` is `T` *(boolean)* + * @param isValid Callback function, that have to return true ro + * @param errorMessage + * @returns */ -function generateAssertPredicate ( +export function generateAsserter ( isValid: (source: unknown, ...args: unknown[]) => source is T | boolean, errorMessage: string ): (checkingVariable: unknown) => asserts checkingVariable is T { @@ -57,34 +55,51 @@ function generateAssertPredicate ( } } - -export interface Predicates { - guard: ReturnType, - asserter: ReturnType -} - -export interface GuardOptions { - prop: keyof T - propPrimitive: string | symbol +export interface Predicates { + guard: ReturnType>, + assert: ReturnType> } -export interface AsserterOptions { - isValid: (source: unknown, ...args: unknown[]) => source is T | boolean - errorMessage: string -} +/** + * @description Generates predicates by provided validation callback + * @param errorMessage Error message `string` for *asserter* + * @param validation Validation `callback`, like in *conditional type guard* + * @returns Object with both asserter and type guard + */ +export function generatePredicates( + errorMessage: string, + validation: (source: unknown, ...args: unknown[]) => boolean +): Predicates /** - * @description Asserter and guard generator - * @param guardOptions Type guard function options - * @param asserterOptions Type asserter function options - * @returns `Predicates` type object, which have asserter and guard bundled in one object + * @description Generates predicates by provided property and its primitive + * @param prop Property to check *(must be string or symbol)* + * @param propPrimitive This property `type` alias primitive in string + * @returns Object with both asserter and type guard */ -export function generatePredicates ( - guardOptions: GuardOptions, - asserterOptions: AsserterOptions -): Predicates { - return { - guard: generateTypeGuard(guardOptions.prop, guardOptions.propPrimitive), - asserter: generateAssertPredicate(asserterOptions.isValid, asserterOptions.errorMessage) +export function generatePredicates( + errorMessage: string, + prop: keyof T, + propPrimitive: string | symbol +): Predicates + +export function generatePredicates( + errorMessage: string, + validationOrProp: keyof T | ((source: unknown, ...args: unknown[]) => boolean), + propPrimitive?: string | symbol +): any { + if (validationOrProp instanceof Function) { + return { + guard: generateConditionalGuard(validationOrProp), + assert: generateAsserter(validationOrProp as (source: unknown, ...args: unknown[]) => source is T | boolean, errorMessage) + } + } else if (propPrimitive) { + const guard = generateGuard(validationOrProp, propPrimitive) + return { + guard, + assert: generateAsserter( + guard, errorMessage + ) + } } } diff --git a/src/functions/propertiesAggregation.ts b/src/functions/propertiesAggregation.ts index 878b3cc..6d7c20d 100644 --- a/src/functions/propertiesAggregation.ts +++ b/src/functions/propertiesAggregation.ts @@ -11,6 +11,7 @@ export const excludeProperties = (source: return source } + /** * * @param source Source object diff --git a/src/types/utility.ts b/src/types/utility.ts index 4c74fbb..d5ad600 100644 --- a/src/types/utility.ts +++ b/src/types/utility.ts @@ -22,8 +22,19 @@ export type ValueOf = T extends unknown[] ? T[number] : T extends object ? T[ */ export type FromArray = T extends (infer U)[] ? U : T -export type ExcludeNullable = T extends object ? DeepRequired : Exclude +/** + * @description Excludes all nullable unions in nested fields + */ +export type ExcludeNullable = T extends object ? { + [P in keyof T]: ExcludeNullable +} : Exclude + +/** + * @description Excludes all primitive types from union type in nested properties + */ +export type ExcludeActual = T extends object ? { + [P in keyof T]: ExcludeActual +} : Exclude -export type ExcludeActual = T extends infer U ? Exclude> : T -export type ActualReturnType = T extends (args: any[]) => Promise ? ExcludeActual>> : T extends (args: any[]) => any ? ExcludeActual> : never +export type ActualReturnType = T extends (args: any[]) => Promise ? ExcludeNullable>> : T extends (args: any[]) => any ? ExcludeNullable> : never diff --git a/tests/functions/predicatesAndTyping.test.d.ts b/tests/functions/predicatesAndTyping.test.d.ts new file mode 100644 index 0000000..9d93ed8 --- /dev/null +++ b/tests/functions/predicatesAndTyping.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=predicatesAndTyping.test.d.ts.map \ No newline at end of file diff --git a/tests/functions/predicatesAndTyping.test.d.ts.map b/tests/functions/predicatesAndTyping.test.d.ts.map new file mode 100644 index 0000000..8c89db6 --- /dev/null +++ b/tests/functions/predicatesAndTyping.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"predicatesAndTyping.test.d.ts","sourceRoot":"","sources":["predicatesAndTyping.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/tests/functions/predicatesAndTyping.test.js b/tests/functions/predicatesAndTyping.test.js new file mode 100644 index 0000000..7f72cb9 --- /dev/null +++ b/tests/functions/predicatesAndTyping.test.js @@ -0,0 +1,140 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const globals_1 = require("@jest/globals"); +const predicatesAndTyping_1 = require("../../src/functions/predicatesAndTyping"); +(0, globals_1.describe)("isSameType function", () => { + (0, globals_1.test)("Testing comparing of same types", () => { + const firstNumber = 0; + const secondNumber = 12; + (0, globals_1.expect)((0, predicatesAndTyping_1.isSameType)(firstNumber, secondNumber)).toEqual(true); + }); + (0, globals_1.test)("Testing comparing of NOT same types", () => { + const number = 0; + const stringArray = []; + (0, globals_1.expect)((0, predicatesAndTyping_1.isSameType)(stringArray, number)).toEqual(false); + }); +}); +(0, globals_1.describe)("generateConditionalGuard function", () => { + const guard = (0, predicatesAndTyping_1.generateConditionalGuard)((variable) => { + return variable.name.charAt(0) === "A"; + }); + (0, globals_1.test)("Testing for guard failure", () => { + const testUser = { + id: 123, + name: "Lisa", + age: 19 + }; + (0, globals_1.expect)(guard(testUser)).toEqual(false); + }); + (0, globals_1.test)("Testing for guard success", () => { + const testUser = { + id: 123, + name: "Alex", + age: 19 + }; + (0, globals_1.expect)(guard(testUser)).toEqual(true); + }); +}); +(0, globals_1.describe)("generateGuard function", () => { + const guard = (0, predicatesAndTyping_1.generateGuard)("name", "string"); + (0, globals_1.test)("Testing for guard failure", () => { + const testUser = { + id: 123, + age: 19 + }; + (0, globals_1.expect)(guard(testUser)).toEqual(false); + }); + (0, globals_1.test)("Testing for guard success", () => { + const testUser = { + id: 123, + name: "Alex", + age: 19 + }; + (0, globals_1.expect)(guard(testUser)).toEqual(true); + }); +}); +// testing both type guard and type asserter via 'generatePredicates' generator with first overload +(0, globals_1.describe)("generatePredicates function (conditional type guard + type asserter)", () => { + const predicates = (0, predicatesAndTyping_1.generatePredicates)("Name does not starts with 'A'", (source) => !source.name.startsWith("A")); + // type guard tests + (0, globals_1.test)("Testing to guard failure", () => { + const testUser = { + id: 123, + name: "Alex", + age: 32 + }; + (0, globals_1.expect)(predicates.guard(testUser)).toEqual(false); + }); + (0, globals_1.test)("Testing to guard success", () => { + const testUser = { + id: 123, + name: "Lisa", + age: 19 + }; + (0, globals_1.expect)(predicates.guard(testUser)).toEqual(true); + }); + // type asserter tests + (0, globals_1.test)("Testing asserter to complete", () => { + const testUser = { + id: 123, + name: "Lisa", + age: 19 + }; + (0, globals_1.expect)(predicates.assert(testUser)).toEqual(undefined); + }); + (0, globals_1.test)("Testing asserter to throw error", () => { + const testUser = { + id: 123, + name: "Alex", + age: 19 + }; + try { + predicates.assert(testUser); + } + catch (error) { + (0, globals_1.expect)(error).toBeDefined(); + } + }); +}); +// testing both type guard and type asserter via 'generatePredicates' generator with first overload +(0, globals_1.describe)("generatePredicates function (default type guard + type asserter)", () => { + const predicates = (0, predicatesAndTyping_1.generatePredicates)("Name is string", "name", "string"); + // type guard tests + (0, globals_1.test)("Testing to guard failure", () => { + const testUser = { + id: 123, + age: 32 + }; + (0, globals_1.expect)(predicates.guard(testUser)).toEqual(false); + }); + (0, globals_1.test)("Testing to guard success", () => { + const testUser = { + id: 123, + name: "Lisa", + age: 19 + }; + (0, globals_1.expect)(predicates.guard(testUser)).toEqual(true); + }); + // type asserter tests + (0, globals_1.test)("Testing asserter to complete", () => { + const testUser = { + id: 123, + name: "Lisa", + age: 19 + }; + (0, globals_1.expect)(predicates.assert(testUser)).toEqual(undefined); + }); + (0, globals_1.test)("Testing asserter to throw error", () => { + const testUser = { + id: 123, + age: 19 + }; + try { + predicates.assert(testUser); + } + catch (error) { + (0, globals_1.expect)(error).toBeDefined(); + } + }); +}); +//# sourceMappingURL=predicatesAndTyping.test.js.map \ No newline at end of file diff --git a/tests/functions/predicatesAndTyping.test.js.map b/tests/functions/predicatesAndTyping.test.js.map new file mode 100644 index 0000000..0101342 --- /dev/null +++ b/tests/functions/predicatesAndTyping.test.js.map @@ -0,0 +1 @@ +{"version":3,"file":"predicatesAndTyping.test.js","sourceRoot":"","sources":["predicatesAndTyping.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/tests/functions/predicatesAndTyping.test.ts b/tests/functions/predicatesAndTyping.test.ts index 8f1a4a7..5341477 100644 --- a/tests/functions/predicatesAndTyping.test.ts +++ b/tests/functions/predicatesAndTyping.test.ts @@ -1,5 +1,5 @@ import { describe, test, expect } from "@jest/globals" -import {isSameType, generateConditionalTypeGuard, generatePredicates, Predicates} from "../../src/functions/predicatesAndTyping" +import {isSameType, generateConditionalGuard, generateAsserter, generateGuard, generatePredicates, Predicates} from "../../src/functions/predicatesAndTyping" describe("isSameType function", () => { @@ -19,19 +19,19 @@ describe("isSameType function", () => { }) -type TestUser = { +type User = { id: number name: string age: number } -describe("generateConditionalTypeGuard function", () => { - const guard = generateConditionalTypeGuard((variable: unknown) => { - return (variable as TestUser).name.charAt(0) === "A" +describe("generateConditionalGuard function", () => { + const guard = generateConditionalGuard((variable: unknown) => { + return (variable as User).name.charAt(0) === "A" }) - test("Testing to guard failure", () => { - const testUser: TestUser = { + test("Testing for guard failure", () => { + const testUser = { id: 123, name: "Lisa", age: 19 @@ -40,8 +40,8 @@ describe("generateConditionalTypeGuard function", () => { expect(guard(testUser)).toEqual(false) }) - test("Testing to guard success", () => { - const testUser: TestUser = { + test("Testing for guard success", () => { + const testUser = { id: 123, name: "Alex", age: 19 @@ -51,23 +51,46 @@ describe("generateConditionalTypeGuard function", () => { }) }) -// testing both type guard and type asserter via 'generatePredicates' generator -describe("generatePredicates function (default type guard + type asserter)", () => { - const predicates: Predicates = generatePredicates( - {prop: "age", propPrimitive: "number"}, - { - isValid: (source: unknown): source is TestUser | boolean => { - return (source as TestUser).name.charAt(0) === "A" - }, - errorMessage: "Name does not starts with 'A'" +describe("generateGuard function", () => { + const guard = generateGuard( + "name", + "string" + ) + + + test("Testing for guard failure", () => { + const testUser = { + id: 123, + age: 19 + } + + expect(guard(testUser)).toEqual(false) + }) + + test("Testing for guard success", () => { + const testUser = { + id: 123, + name: "Alex", + age: 19 } + + expect(guard(testUser)).toEqual(true) + }) +}) + +// testing both type guard and type asserter via 'generatePredicates' generator with first overload +describe("generatePredicates function (conditional type guard + type asserter)", () => { + const predicates: Predicates = generatePredicates( + "Name does not starts with 'A'", + (source: unknown) => !(source as User).name.startsWith("A") ) // type guard tests test("Testing to guard failure", () => { const testUser = { id: 123, - name: "Alex" + name: "Alex", + age: 32 } expect(predicates.guard(testUser)).toEqual(false) @@ -75,7 +98,7 @@ describe("generatePredicates function (default type guard + type asserter)", () test("Testing to guard success", () => { - const testUser: TestUser = { + const testUser = { id: 123, name: "Lisa", age: 19 @@ -86,24 +109,76 @@ describe("generatePredicates function (default type guard + type asserter)", () // type asserter tests test("Testing asserter to complete", () => { - const testUser: TestUser = { + const testUser = { id: 123, - name: "Alex", + name: "Lisa", age: 19 } - expect(predicates.asserter(testUser)).toEqual(undefined) + expect(predicates.assert(testUser)).toEqual(undefined) }) test("Testing asserter to throw error", () => { - const testUser: TestUser = { + const testUser = { + id: 123, + name: "Alex", + age: 19 + } + try { + + predicates.assert(testUser) + } catch (error) { + expect(error).toBeDefined() + } + }) +}) + + +// testing both type guard and type asserter via 'generatePredicates' generator with first overload +describe("generatePredicates function (default type guard + type asserter)", () => { + const predicates: Predicates = generatePredicates( + "Name is string", + "name", + "string" + ) + + // type guard tests + test("Testing to guard failure", () => { + const testUser = { + id: 123, + age: 32 + } + + expect(predicates.guard(testUser)).toEqual(false) + }) + + test("Testing to guard success", () => { + const testUser = { + id: 123, + name: "Lisa", + age: 19 + } + + expect(predicates.guard(testUser)).toEqual(true) + }) + + // type asserter tests + test("Testing asserter to complete", () => { + const testUser = { id: 123, name: "Lisa", age: 19 } + expect(predicates.assert(testUser)).toEqual(undefined) + }) + test("Testing asserter to throw error", () => { + const testUser = { + id: 123, + age: 19 + } try { - predicates.asserter(testUser) + predicates.assert(testUser) } catch (error) { expect(error).toBeDefined() } diff --git a/tests/functions/propertiesAggregation.test.d.ts b/tests/functions/propertiesAggregation.test.d.ts new file mode 100644 index 0000000..3cae35f --- /dev/null +++ b/tests/functions/propertiesAggregation.test.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=propertiesAggregation.test.d.ts.map \ No newline at end of file diff --git a/tests/functions/propertiesAggregation.test.d.ts.map b/tests/functions/propertiesAggregation.test.d.ts.map new file mode 100644 index 0000000..d671638 --- /dev/null +++ b/tests/functions/propertiesAggregation.test.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"propertiesAggregation.test.d.ts","sourceRoot":"","sources":["propertiesAggregation.test.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/tests/functions/propertiesAggregation.test.js b/tests/functions/propertiesAggregation.test.js new file mode 100644 index 0000000..0ab5d95 --- /dev/null +++ b/tests/functions/propertiesAggregation.test.js @@ -0,0 +1,19 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const globals_1 = require("@jest/globals"); +const propertiesAggregation_1 = require("../../src/functions/propertiesAggregation"); +(0, globals_1.describe)("excludeProperties function", () => { + (0, globals_1.test)("Excluding properties", () => { + const initialObject = { a: 12, b: 23, c: 45 }; + (0, globals_1.expect)((0, propertiesAggregation_1.excludeProperties)(initialObject, "a", "b")).toEqual({ c: 45 }); + (0, globals_1.expect)(initialObject).toEqual({ c: 45 }); + }); +}); +(0, globals_1.describe)("pickProperties function", () => { + (0, globals_1.test)("Picking properties", () => { + const initialObject = { a: 12, b: 23, c: 45 }; + (0, globals_1.expect)((0, propertiesAggregation_1.pickProperties)(initialObject, "a", "b")).toEqual({ a: 12, b: 23 }); + (0, globals_1.expect)(initialObject).toEqual({ a: 12, b: 23 }); + }); +}); +//# sourceMappingURL=propertiesAggregation.test.js.map \ No newline at end of file diff --git a/tests/functions/propertiesAggregation.test.js.map b/tests/functions/propertiesAggregation.test.js.map new file mode 100644 index 0000000..5ecd2bb --- /dev/null +++ b/tests/functions/propertiesAggregation.test.js.map @@ -0,0 +1 @@ +{"version":3,"file":"propertiesAggregation.test.js","sourceRoot":"","sources":["propertiesAggregation.test.ts"],"names":[],"mappings":";;AAAA,2CAAsD;AACtD,qFAA2F;AAE3F,IAAA,kBAAQ,EAAC,4BAA4B,EAAE,GAAG,EAAE;IACxC,IAAA,cAAI,EAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,aAAa,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAA;QAC7C,IAAA,gBAAM,EACF,IAAA,yCAAiB,EAAC,aAAa,EAAE,GAAG,EAAE,GAAG,CAAC,CAC7C,CAAC,OAAO,CAAC,EAAC,CAAC,EAAE,EAAE,EAAC,CAAC,CAAA;QAElB,IAAA,gBAAM,EAAC,aAAa,CAAC,CAAC,OAAO,CAAC,EAAC,CAAC,EAAE,EAAE,EAAC,CAAC,CAAA;IAC1C,CAAC,CAAC,CAAA;AACN,CAAC,CAAC,CAAA;AAGF,IAAA,kBAAQ,EAAC,yBAAyB,EAAE,GAAG,EAAE;IACrC,IAAA,cAAI,EAAC,oBAAoB,EAAE,GAAG,EAAE;QAC5B,MAAM,aAAa,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAA;QAC7C,IAAA,gBAAM,EACF,IAAA,sCAAc,EAAC,aAAa,EAAE,GAAG,EAAE,GAAG,CAAC,CAC1C,CAAC,OAAO,CAAC,EAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAC,CAAC,CAAA;QAEzB,IAAA,gBAAM,EAAC,aAAa,CAAC,CAAC,OAAO,CAAC,EAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAC,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;AACN,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 4dab0df..738b955 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,7 +26,7 @@ /* Modules */ "module": "NodeNext", /* Specify what module code is generated. */ - "rootDir": "./src", /* Specify the root folder within your source files. */ + "rootDir": "./", /* Specify the root folder within your source files. */ "moduleResolution": "NodeNext", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */