@mephisto5558/better-types 1.0.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
Binary file
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@mephisto5558/better-types",
3
- "version": "1.0.1",
3
+ "version": "2.0.0",
4
4
  "description": "A collection of useful TypeScript types and augmentations to improve developer experience.",
5
5
  "keywords": [
6
- "typing",
7
- "typescript"
6
+ "typescript",
7
+ "typing"
8
8
  ],
9
9
  "homepage": "https://github.com/Mephisto5558/Better-Types#readme",
10
10
  "bugs": {
@@ -19,17 +19,20 @@
19
19
  "type": "module",
20
20
  "exports": {
21
21
  ".": {
22
- "types": "./index.d.ts"
22
+ "types": "./src/index.d.ts"
23
23
  },
24
- "./eslint": "./eslint.js"
24
+ "./eslint": {
25
+ "types": "./src/eslint.d.ts",
26
+ "import": "./src/eslint.js",
27
+ "require": "./src/eslint.js"
28
+ }
25
29
  },
26
- "types": "index.d.ts",
30
+ "types": "src/index.d.ts",
27
31
  "files": [
28
- "index.d.ts",
29
- "eslint.js",
30
- "eslint.d.ts"
32
+ "src"
31
33
  ],
32
34
  "scripts": {
35
+ "lint": "eslint . --cache --cache-location ./node_modules/.cache/eslint/ >eslint.log",
33
36
  "test": "echo \"Error: no test specified\" && exit 1"
34
37
  },
35
38
  "devDependencies": {
@@ -43,5 +46,12 @@
43
46
  },
44
47
  "engines": {
45
48
  "node": ">=20"
49
+ },
50
+ "devEngines": {
51
+ "runtime": {
52
+ "name": "node",
53
+ "onFail": "error",
54
+ "version": ">=20"
55
+ }
46
56
  }
47
57
  }
package/src/eslint.js ADDED
@@ -0,0 +1,57 @@
1
+ /* eslint-disable-next-line import-x/prefer-default-export -- easier import */
2
+ export const globals = Object.freeze(Object.fromEntries([
3
+ 'Snowflake',
4
+ 'GenericFunction',
5
+ 'GenericConstructor',
6
+ 'OmitFirstParameters',
7
+ 'ReplaceMethods',
8
+ 'Prettify',
9
+ 'ShallowPrettify',
10
+
11
+ // logicShortcuts/normal.ts
12
+ 'If',
13
+ 'IfD',
14
+ 'IfEquals',
15
+ 'IfExtends',
16
+ 'IfExtendsD',
17
+ 'AddIf',
18
+ 'Extends',
19
+ 'GetAll',
20
+ 'And',
21
+ 'Or',
22
+ 'Not',
23
+ 'Match',
24
+ 'ExtendsMatch',
25
+ 'ExtendsMultiMatch',
26
+ 'Fn',
27
+ 'IsEmptyArray',
28
+ 'LooseOmit',
29
+
30
+ // logicShortcuts/strict.ts
31
+ 'IfExtendsStrict',
32
+ 'IfExtendsStrictD',
33
+ 'IfExtendsNever',
34
+ 'ExtendsStrict',
35
+ 'ExtendsNever',
36
+ 'ExtendsMatchStrict',
37
+ 'ExtendsMultiMatchStrict',
38
+ 'StrictPick',
39
+ 'GetAllStrict',
40
+ 'StrictOmit',
41
+
42
+ // better-typescript-lib
43
+ 'JSONPrimitive',
44
+ 'JSONComposite',
45
+ 'JSONValueF',
46
+ 'JSONValue',
47
+ 'JSONObject',
48
+ 'JSONHolder',
49
+ 'ToJSON',
50
+ 'SomeExtends',
51
+
52
+ // "SomeFunction", // use GenericFunction instead
53
+ 'SomeConstructor',
54
+ 'UndefinedDomain',
55
+ 'StringifyResultT',
56
+ 'StringifyResult'
57
+ ].map(e => [e, 'readonly'])));
@@ -1,33 +1,24 @@
1
1
  /* eslint-disable-next-line @typescript-eslint/triple-slash-reference -- required to load before this file when this lib is loaded locally */
2
2
  /// <reference types="node" />
3
3
 
4
- /* eslint-disable sonarjs/no-built-in-override */
4
+ /* eslint-disable @typescript-eslint/triple-slash-reference, @stylistic/multiline-comment-style
5
+ -- required to load other globals without affecting the global scope */
6
+ /// <reference path="./logicShortcuts/normal.d.ts" />
7
+ /// <reference path="./logicShortcuts/strict.d.ts" />
8
+ /* eslint-enable @typescript-eslint/triple-slash-reference, @stylistic/multiline-comment-style */
5
9
 
10
+ /* eslint-disable sonarjs/no-built-in-override -- overwriting builtins */
11
+
12
+ import type { AssignThis, ISODateTime, KeyToString, Split, StripExtension, _Prettify } from './utils.js';
6
13
  /* eslint-disable-next-line unicorn/require-module-specifiers -- required */
7
14
  export {};
8
15
 
9
- type ISODate = `${number}${number}${number}${number}-${number}${number}-${number}${number}`;
10
- type ISOTime = `${number}${number}:${number}${number}:${number}${number}.${number}${number}${number}`;
11
- type ISODateTime = `${ISODate}T${ISOTime}Z`;
12
-
13
- type KeyToString<K extends PropertyKey> = K extends string ? K : K extends number ? `${K}` : never;
14
-
15
- type Split<S extends string, SEP extends string | undefined, L extends number = number, Acc extends string[] = []> = SEP extends unknown
16
- ? [L] extends [Acc['length']] ? Acc
17
- : SEP extends undefined ? [S]
18
- : string extends S | SEP ? string[]
19
- : SEP extends ''
20
- ? S extends `${infer Head}${infer Tail}`
21
- ? Split<Tail, SEP, L, [...Acc, Head]>
22
- : Acc
23
- : S extends `${infer Head}${SEP}${infer Tail}`
24
- ? Split<Tail, SEP, L, [...Acc, Head]>
25
- : [...Acc, S]
26
- : never;
27
-
28
16
  declare global {
17
+ /** The maximum depth for {@link Prettify}. Change with caution. */
18
+ type __MAX_PRETTIFY_DEPTH = 5;
19
+
29
20
  // #region Buildins
30
- /* eslint-disable @typescript-eslint/consistent-type-definitions */
21
+ /* eslint-disable @typescript-eslint/consistent-type-definitions -- overwriting interfaces */
31
22
  namespace NodeJS {
32
23
  interface Require {
33
24
  /* eslint-disable-next-line @typescript-eslint/prefer-function-type -- overwriting only the function signature */
@@ -79,20 +70,42 @@ declare global {
79
70
  /* eslint-enable @typescript-eslint/consistent-type-definitions */
80
71
 
81
72
  // #region useful Generics
82
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any -- used only as generic constraint */
83
- type GenericFunction<Ret = any> = (...args: any) => Ret;
73
+ /* eslint-disable @typescript-eslint/no-explicit-any -- used only as generic constraint */
74
+
75
+ /** A function with some parameters and some return type. */
76
+ type GenericFunction<Ret = any> = (...args: any[]) => Ret;
77
+
78
+ /** A potentially abstract class or declared class. */
79
+ type GenericConstructor<Ret = object> = { prototype: Ret };
80
+
81
+ /* eslint-enable @typescript-eslint/no-explicit-any */
84
82
 
85
83
  type OmitFirstParameters<
86
84
  T extends GenericFunction, N extends number = 1, Acc extends unknown[] = []
87
85
  > = Acc['length'] extends N ? Parameters<T> extends [...Acc, ...infer Rest] ? Rest : never : OmitFirstParameters<T, N, [...Acc, unknown]>;
88
86
 
89
- /**
90
- * A stricter version of `Omit` that preserves modifiers better by using a mapped type.
91
- *
92
- * {@link https://github.com/microsoft/TypeScript/issues/54451#issue-1732749888 More info} */
93
- type StrictOmit<T, K extends keyof T> = { [P in keyof T as P extends K ? never : P]: T[P] };
94
-
95
- type ReplaceMethod<T, K extends keyof T, This, Args extends unknown[] = Parameters<T[K]>> = StrictOmit<T, K> & {
96
- [P in K]: Exclude<T[P], GenericFunction> | ((this: This, ...args: Args) => ReturnType<Extract<T[P], GenericFunction>>);
87
+ type ReplaceMethods<T, ContextMap extends Partial<Record<keyof T, unknown>>> = {
88
+ [K in keyof T]: K extends keyof ContextMap
89
+ ? AssignThis<T[K], ContextMap[K]>
90
+ : T[K];
97
91
  };
92
+
93
+ type Prettify<T> = _Prettify<T, true>;
94
+ type ShallowPrettify<T> = _Prettify<T, false>;
95
+ }
96
+
97
+ declare module 'node:path' {
98
+ export function basename<P extends string, E extends string | undefined = undefined>(
99
+ path: P, ext?: E
100
+ ): Lowercase<P> extends P ? Lowercase<StripExtension<P, E>> : StripExtension<P, E>;
101
+
102
+ export function extname<T extends string>(path: T): T extends Lowercase<string> ? Lowercase<string> : string;
103
+ }
104
+
105
+ declare module 'path' {
106
+ export * from 'node:path';
107
+ }
108
+
109
+ declare module 'discord-api-types/v10' {
110
+ export type Snowflake = globalThis.Snowflake;
98
111
  }
@@ -0,0 +1,2 @@
1
+ export type BooleanOptions = { ifTrue?: unknown; ifFalse?: unknown };
2
+ export type ResolveBooleanResult<O extends BooleanOptions, K extends keyof BooleanOptions> = K extends keyof O ? O[K] : never;
@@ -0,0 +1,111 @@
1
+ import type { BooleanOptions, ResolveBooleanResult } from './index.js';
2
+ import type { AllKeys } from '#/utils.js';
3
+
4
+ /* eslint-disable-next-line unicorn/require-module-specifiers -- required */
5
+ export {};
6
+
7
+ declare global {
8
+
9
+ /**
10
+ * Resolves to 'Options.ifTrue` if 'Condition` resolves to `true`,
11
+ * otherwise to `Options.ifFalse`.
12
+ *
13
+ * Defaults to `never` for either result. */
14
+ type If<Condition extends boolean, Options extends BooleanOptions>
15
+ = Condition extends true
16
+ ? ResolveBooleanResult<Options, 'ifTrue'>
17
+ : ResolveBooleanResult<Options, 'ifFalse'>
18
+ ;
19
+
20
+ /** Non-Object version of {@link If} to support use of `this`. */
21
+ type IfD<Condition extends boolean, IfTrue, IfFalse> = NoInfer<Condition> extends true ? IfTrue : IfFalse;
22
+
23
+ type IfEquals<A, B, Options extends BooleanOptions> = Prettify<
24
+ /* eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- these are nessesary. */
25
+ (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2)
26
+ ? ResolveBooleanResult<Options, 'ifTrue'>
27
+ : ResolveBooleanResult<Options, 'ifFalse'>
28
+ >;
29
+
30
+ /**
31
+ * Resolves to `Options.ifTrue` if `T` extends `Type`,
32
+ * otherwise to `Options.ifFalse`.
33
+ *
34
+ * Defaults to `never` for either result. */
35
+ type IfExtends<T, Type, Options extends BooleanOptions> = Prettify<
36
+ T extends NoInfer<Type>
37
+ ? ResolveBooleanResult<Options, 'ifTrue'>
38
+ : ResolveBooleanResult<Options, 'ifFalse'>
39
+ >;
40
+
41
+ /** Non-Object version of {@link IfExtends} to support use of `this`. */
42
+ type IfExtendsD<T, Type, IfTrue, IfFalse> = T extends NoInfer<Type> ? IfTrue : IfFalse;
43
+
44
+ /**
45
+ * Adds `Options.ifTrue` to `Base` if `Condition` resolves to `true`,
46
+ * otherwise adds `Options.ifFalse`.
47
+ *
48
+ * Defaults to `never` for either result. */
49
+ type AddIf<Base, Condition extends boolean, Options extends BooleanOptions> = Prettify<
50
+ NoInfer<Condition> extends true
51
+ ? Base | ResolveBooleanResult<Options, 'ifTrue'>
52
+ : Base | ResolveBooleanResult<Options, 'ifFalse'>
53
+ >;
54
+
55
+ /** Resolves to `true` if `T extends Type`, otherwise to `false`. */
56
+ type Extends<T, Type> = T extends NoInfer<Type> ? true : false;
57
+
58
+ /** Extract from `T` those types that have might have a property of key `K`. */
59
+ type GetAll<T, K extends AllKeys<T>> = Extract<T, Partial<Record<K, unknown>>>;
60
+
61
+ type And<T extends readonly [boolean, boolean, ...boolean[]]>
62
+ = NoInfer<T>[number] extends true ? true : false;
63
+
64
+ type Or<T extends readonly [boolean, boolean, ...boolean[]]>
65
+ = true extends NoInfer<T>[number] ? true : false;
66
+
67
+ type Not<T extends boolean> = NoInfer<T> extends true ? false : true;
68
+
69
+ type Match<Cases extends readonly (readonly [boolean, unknown])[], Default = never>
70
+ = Cases extends readonly [readonly [infer Condition, infer Result], ...infer Rest]
71
+ ? NoInfer<Condition> extends true
72
+ ? Result
73
+ : Rest extends readonly (readonly [boolean, unknown])[]
74
+ ? Match<Rest, Default>
75
+ : Default
76
+ : Default;
77
+
78
+ type ExtendsMatch<T, Cases extends readonly (readonly [unknown, unknown])[], Default = never>
79
+ = Cases extends readonly [readonly [infer Condition, infer Result], ...infer Rest]
80
+ ? T extends NoInfer<Condition>
81
+ ? Result
82
+ : Rest extends readonly (readonly [unknown, unknown])[]
83
+ ? ExtendsMatch<T, Rest, Default>
84
+ : Default
85
+ : Default;
86
+
87
+ type ExtendsMultiMatch<
88
+ BASE,
89
+ KEYS extends readonly BASE[],
90
+ Cases extends readonly (readonly [BASE, unknown])[]
91
+ > = ShallowPrettify<
92
+ { [I in keyof KEYS]: ExtendsMatch<KEYS[I], NoInfer<Cases>> }[number]
93
+ >;
94
+
95
+ type Fn<This, Args extends unknown[], Return> = Prettify<
96
+ NoInfer<This> extends never
97
+ ? (...args: NoInfer<Args>) => NoInfer<Return>
98
+ : (this: This, ...args: NoInfer<Args>) => NoInfer<Return>
99
+ >;
100
+
101
+ /**
102
+ * Resolves to `true` if the `Arr`'s length is `0`,
103
+ * `false` if it's not, and `boolean` if we don't know. */
104
+ type IsEmptyArray<Arr extends readonly unknown[]>
105
+ = number extends Arr['length']
106
+ ? boolean
107
+ : [Arr['length']] extends [0] ? true : false;
108
+
109
+ /** A loose implementation of {@link StrictOmit} that allows any `PropertyKey`s for `K`. */
110
+ type LooseOmit<T, K extends PropertyKey> = Pick<T, Exclude<keyof T, K>>;
111
+ }
@@ -0,0 +1,67 @@
1
+ import type { BooleanOptions, ResolveBooleanResult } from './index.js';
2
+ import type { AllKeys } from '#/utils.js';
3
+
4
+ /* eslint-disable-next-line unicorn/require-module-specifiers -- required */
5
+ export {};
6
+
7
+ declare global {
8
+ /** Non-distributive version of {@link IfExtends}. */
9
+ type IfExtendsStrict<T, Type, Options extends BooleanOptions> = Prettify<
10
+ [T] extends [NoInfer<Type>]
11
+ ? ResolveBooleanResult<Options, 'ifTrue'>
12
+ : ResolveBooleanResult<Options, 'ifFalse'>
13
+ >;
14
+
15
+ /** Non-Object version of {@link IfExtendsStrict} to support use of `this`. */
16
+ type IfExtendsStrictD<T, Type, IfTrue, IfFalse>
17
+ = [T] extends [NoInfer<Type>] ? IfTrue : IfFalse;
18
+
19
+ /** Shortcut of {@link IfExtendsStrict} to check if a type extends never. */
20
+ type IfExtendsNever<T, Options extends BooleanOptions> = [T] extends [never]
21
+ ? ResolveBooleanResult<Options, 'ifTrue'>
22
+ : ResolveBooleanResult<Options, 'ifFalse'>;
23
+
24
+ /** Non-distributive version of {@link Extends}. */
25
+ type ExtendsStrict<T, Type> = [T] extends [NoInfer<Type>] ? true : false;
26
+
27
+ /** Shortcut of {@link ExtendsStrict} to check if a type extends never. */
28
+ type ExtendsNever<T> = [T] extends [never] ? true : false;
29
+
30
+ /** Non-distributive version of {@link ExtendsMatch}. */
31
+ type ExtendsMatchStrict<T, Cases extends readonly (readonly [unknown, unknown])[], Default = never>
32
+ = Cases extends readonly [readonly [infer Condition, infer Result], ...infer Rest]
33
+ ? [T] extends [NoInfer<Condition>]
34
+ ? Result
35
+ : Rest extends readonly (readonly [unknown, unknown])[]
36
+ ? ExtendsMatchStrict<T, Rest, Default>
37
+ : Default
38
+ : Default;
39
+
40
+ /** Non-distributive version of {@link ExtendsMultiMatch}. */
41
+ type ExtendsMultiMatchStrict<
42
+ BASE,
43
+ KEYS extends readonly BASE[],
44
+ Cases extends readonly (readonly [BASE, unknown])[]
45
+ > = Prettify<
46
+ { [I in keyof KEYS]: ExtendsMatchStrict<KEYS[I], NoInfer<Cases>> }[number]
47
+ >;
48
+
49
+ /**
50
+ * Strict version of {@link Pick}. Validates that all keys in `Target` exist in `Base`.
51
+ * Keys not present in `Base` are resolved to `never`. */
52
+ type StrictPick<Target, Base> = {
53
+ [K in keyof Target]: K extends keyof Base ? Target[K] : never;
54
+ };
55
+
56
+ /** Strict Version of {@link GetAll} that does not allow `K` to be optional. */
57
+ type GetAllStrict<T, K extends AllKeys<T>> = Extract<T, Record<K, unknown>>;
58
+
59
+ // /**
60
+ // * A stricter version of `Omit` that preserves modifiers better by using a mapped type.
61
+ // *
62
+ // * {@link https://github.com/microsoft/TypeScript/issues/54451#issue-1732749888 More info} */
63
+ // type StrictOmit<T, K extends keyof T> = { [P in keyof T as P extends K ? never : P]: T[P] };
64
+
65
+ /** A stricter version of `Omit` that keeps interfaces' identity using `Pick` and `Exclude`. */
66
+ type StrictOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
67
+ }
package/src/utils.d.ts ADDED
@@ -0,0 +1,46 @@
1
+ type ISODate = `${number}${number}${number}${number}-${number}${number}-${number}${number}`;
2
+ type ISOTime = `${number}${number}:${number}${number}:${number}${number}.${number}${number}${number}`;
3
+ export type ISODateTime = `${ISODate}T${ISOTime}Z`;
4
+
5
+ export type KeyToString<K extends PropertyKey> = K extends string ? K : K extends number ? `${K}` : never;
6
+
7
+ export type Split<S extends string, SEP extends string | undefined, L extends number = number, Acc extends string[] = []> = SEP extends unknown
8
+ ? [L] extends [Acc['length']] ? Acc
9
+ : SEP extends undefined ? [S]
10
+ : string extends S | SEP ? string[]
11
+ : SEP extends ''
12
+ ? S extends `${infer Head}${infer Tail}`
13
+ ? Split<Tail, SEP, L, [...Acc, Head]>
14
+ : Acc
15
+ : S extends `${infer Head}${SEP}${infer Tail}`
16
+ ? Split<Tail, SEP, L, [...Acc, Head]>
17
+ : [...Acc, S]
18
+ : never;
19
+
20
+ type ProbablyDiscordJs = { client: unknown };
21
+ type ShouldSkip<T> = [T] extends [object]
22
+ ? T extends ProbablyDiscordJs | GenericFunction | GenericConstructor | { constructor: GenericConstructor }
23
+ ? true
24
+ : false
25
+ : true;
26
+
27
+ export type _Prettify<T, Deep extends boolean, Depth extends unknown[] = []>
28
+ = ShouldSkip<T> extends true ? T
29
+ : Depth['length'] extends __MAX_PRETTIFY_DEPTH ? T : {
30
+ [K in keyof T]: Deep extends true
31
+ ? _Prettify<T[K], Deep, [...Depth, unknown]>
32
+ : T[K]
33
+ } & {};
34
+
35
+ export type StripExtension<T extends string, Ext extends string | undefined>
36
+ = Ext extends string
37
+ ? T extends `${infer R}${Ext}`
38
+ ? R
39
+ : T
40
+ : T;
41
+
42
+ export type AllKeys<T> = T extends unknown ? keyof T : never;
43
+
44
+ export type AssignThis<F, This> = F extends (...args: infer Args) => infer Return
45
+ ? (this: This, ...args: Args) => Return
46
+ : F;
package/eslint.js DELETED
@@ -1,25 +0,0 @@
1
- /* eslint-disable-next-line import-x/prefer-default-export */
2
- export const globals = Object.freeze({
3
- GenericFunction: 'readonly',
4
- OmitFirstParameters: 'readonly',
5
- StrictOmit: 'readonly',
6
- ReplaceMethod: 'readonly',
7
- Snowflake: 'readonly',
8
-
9
-
10
- // better-typescript-lib
11
- JSONPrimitive: 'readonly',
12
- JSONComposite: 'readonly',
13
- JSONValueF: 'readonly',
14
- JSONValue: 'readonly',
15
- JSONObject: 'readonly',
16
- JSONHolder: 'readonly',
17
- ToJSON: 'readonly',
18
- SomeExtends: 'readonly',
19
-
20
- // SomeFunction: 'readonly', // use GenericFunction instead
21
- SomeConstructor: 'readonly',
22
- UndefinedDomain: 'readonly',
23
- StringifyResultT: 'readonly',
24
- StringifyResult: 'readonly'
25
- });
File without changes