diff --git a/packages/type-helper/README.md b/packages/type-helper/README.md new file mode 100644 index 00000000..2667ee14 --- /dev/null +++ b/packages/type-helper/README.md @@ -0,0 +1,26 @@ +# Typescript Type Helpers + +Collection of useful typescript type helpers. + +## Installation + +```bash +yarn add @alwatr/type-helper +``` + +## Usage + +```typescript +import type {JSONObject} from '@alwatr/type-helper'; + +const obj: JSONObject = { + foo: 'bar', + baz: { + qux: 1, + arr: [1, 2, 3], + }, + qux: true, +}; +``` + +Read the [source code](https://github.com/Alwatr/nanolib/tree/next/packages/type-helper/src) for more details. diff --git a/packages/type-helper/package.json b/packages/type-helper/package.json new file mode 100644 index 00000000..85313a59 --- /dev/null +++ b/packages/type-helper/package.json @@ -0,0 +1,56 @@ +{ + "name": "@alwatr/type-helper", + "version": "1.0.0", + "description": "Collection of useful typescript type helpers.", + "author": "S. Ali Mihandoost ", + "keywords": [ + "type", + "type-helper", + "types", + "typescript", + "utility", + "util", + "utils", + "nanolib", + "alwatr" + ], + "main": "", + "types": "./dist/main.d.ts", + "license": "MIT", + "files": [ + "**/*.{js,mjs,cjs,map,d.ts,html,md}", + "!demo/**/*" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/Alwatr/nanolib", + "directory": "packages/type-helper" + }, + "homepage": "https://github.com/Alwatr/nanolib/tree/next/packages/type-helper#readme", + "bugs": { + "url": "https://github.com/Alwatr/nanolib/issues" + }, + "prettier": "@alwatr/prettier-config", + "scripts": { + "b": "yarn run build", + "w": "yarn run watch", + "c": "yarn run clean", + "cb": "yarn run clean && yarn run build", + "d": "yarn run build:es && ALWATR_DEBUG=1 yarn node", + "build": "yarn run build:ts", + "build:es": "echo skip build:es", + "build:ts": "tsc --build", + "watch": "yarn run watch:ts & yarn run watch:es", + "watch:es": "yarn run build:es --watch", + "watch:ts": "yarn run build:ts --watch --preserveWatchOutput", + "clean": "rm -rfv dist *.tsbuildinfo" + }, + "devDependencies": { + "@alwatr/prettier-config": "workspace:^", + "@alwatr/tsconfig-base": "workspace:^", + "typescript": "^5.3.3" + } +} diff --git a/packages/type-helper/src/main.ts b/packages/type-helper/src/main.ts new file mode 100644 index 00000000..99a1ab99 --- /dev/null +++ b/packages/type-helper/src/main.ts @@ -0,0 +1,192 @@ +/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/consistent-indexed-object-style */ + +/** + * Represents a primitive type in TypeScript. + * @typedef {string | number | bigint | boolean | symbol | null | undefined} Primitive + */ +export type Primitive = string | number | bigint | boolean | symbol | null | undefined; + +/** + * Represents a type that includes all falsy values: false, '', 0, null, and undefined. + */ +export type Falsy = false | '' | 0 | null | undefined; + +/** + * Represents a type that can be null or undefined. + */ +export type Nullish = null | undefined; + +/** + * Represents a type that can be either a value of type T or null. + * @template T - The type of the value. + */ +export type Nullable = T | null; + +/** + * Represents a type that can either be of type T or undefined. + * @template T - The type parameter. + */ +export type Maybe = T | undefined; + +/** + * Represents a type that can either be a value of type T or a promise that resolves to a value of type T. + * @template T - The type of the value or the resolved value. + */ +export type MaybePromise = T | Promise; + +/** + * Represents a type that can be either a single value or an array of values. + * @template T - The type of the value(s). + */ +export type SingleOrArray = T | T[]; + +/** + * Type helper that removes the undefined type from a given type. + * @template T The type to remove undefined from. + * @returns The type without undefined. + */ +export type NonUndefined = T extends undefined ? never : T; + +/** + * Returns the keys of an object type `T` that are required (not optional). + * + * @template T - The object type. + * @returns The keys of `T` that are required. + */ +export type RequiredKeys = { + [K in keyof T]-?: {} extends Pick ? never : K; +}[keyof T]; + +/** + * Returns the keys of an object type `T` that are optional. + * + * @template T - The object type. + * @returns The keys of `T` that are optional. + */ +export type OptionalKeys = { + [K in keyof T]-?: {} extends Pick ? K : never; +}[keyof T]; + +/** + * Represents a type that makes all properties of an object and its nested objects readonly. + * @template T - The type to make readonly. + * @returns The readonly version of the input type. + */ +export type DeepReadonly = T extends ((...args: any[]) => any) | Primitive + ? T + : T extends DeepReadonlyArray_ + ? DeepReadonlyArray_ + : T extends DeepReadonlyObject_ + ? DeepReadonlyObject_ + : T; +type DeepReadonlyArray_ = readonly DeepReadonly[]; +type DeepReadonlyObject_ = { + readonly [P in keyof T]: DeepReadonly; +}; + +/** + * Recursively makes all properties of an object and its nested objects/array required. + * + * @template T - The type to make deep required. + * @param {T} value - The value to make deep required. + * @returns {DeepRequired} - The deep required type. + */ +export type DeepRequired = T extends (...args: any[]) => any + ? T + : T extends any[] + ? DeepRequiredArray_ + : T extends object + ? DeepRequiredObject_ + : T; +type DeepRequiredArray_ = DeepRequired>[]; +type DeepRequiredObject_ = { + [P in keyof T]-?: DeepRequired>; +}; + +/** + * Represents a type that makes all properties of the given type optional recursively. + * @template T - The type to make partial. + */ +export type DeepPartial = {[P in keyof T]?: DeepPartial_}; +type DeepPartial_ = T extends ((...args: any[]) => any) | Primitive + ? T + : T extends (infer U)[] + ? DeepPartialArray_ + : T extends object + ? DeepPartial + : T | undefined; +type DeepPartialArray_ = DeepPartial_[]; + +/** + * Represents a class constructor. + * @template T - The type of the class. + */ +export type Class = new (...args: any[]) => T; + +/** + * Removes the first parameter from a function type. + * @template F The function type. + * @returns A new function type without the first parameter. + */ +export type OmitFirstParam = F extends (x: any, ...args: infer A) => infer R ? (...args: A) => R : never; + +/** + * Retrieves the type of a property from an object type. + * + * @template T - The object type. + * @template K - The property key. + * @returns {Prop} - The type of the property. + */ +export type Prop = K extends keyof T ? T[K] : never; + +/** + * Retrieves the union of all values in the given object type. + * @typeparam T - The object type. + * @returns The union of all values in the object type. + */ +export type Values = T[keyof T]; + +/** + * Extracts the type of individual items in an array. + * If the input type is an array, it returns the type of the array items. + * If the input type is not an array, it returns the input type itself. + * + * @typeParam T - The input type. + * @returns The type of individual items in the array, or the input type itself. + */ +export type ArrayItems = T extends (infer K)[] ? K : T; + +/** + * Merges two types together by omitting keys from the first type that exist in the second type, + * and then combining the remaining keys with the keys from the second type. + * @template M - The first type to merge. + * @template N - The second type to merge. + * @returns A new type that is the result of merging the two input types. + */ +export type Merge = Omit & N; + +/** + * Represents a dictionary object with string keys and values of type T. + */ +export interface Dictionary { + [key: string]: T; +} + +/** + * Strigifyable JSON value + */ +/** + * Represents a JSON value that can be of type string, number, boolean, null, undefined, + * JSONArray, or JSONObject. + */ +export type JSONValue = string | number | boolean | null | undefined | JSONArray | JSONObject; + +/** + * Represents an array of JSONValues. + */ +type JSONArray = JSONValue[]; + +/** + * Represents an object of Record + */ +type JSONObject = Dictionary; diff --git a/packages/type-helper/tsconfig.json b/packages/type-helper/tsconfig.json new file mode 100644 index 00000000..eadbf307 --- /dev/null +++ b/packages/type-helper/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@alwatr/tsconfig-base/tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declarationMap": false, + "emitDeclarationOnly": true, + "composite": true, + }, + "include": ["src/**/*.ts"] +}