lay-sing 0.2.0 → 0.2.1

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.
Files changed (92) hide show
  1. package/README.md +55 -16
  2. package/esm/main/async.d.ts +9 -1
  3. package/esm/main/async.d.ts.map +1 -1
  4. package/esm/main/async.js.map +1 -1
  5. package/esm/main/boolean.d.ts +43 -19
  6. package/esm/main/boolean.d.ts.map +1 -1
  7. package/esm/main/boolean.js.map +1 -1
  8. package/esm/main/control.d.ts +65 -36
  9. package/esm/main/control.d.ts.map +1 -1
  10. package/esm/main/control.js.map +1 -1
  11. package/esm/main/doc.d.ts +33 -7
  12. package/esm/main/doc.d.ts.map +1 -1
  13. package/esm/main/doc.js.map +1 -1
  14. package/esm/main/function.d.ts +11 -3
  15. package/esm/main/function.d.ts.map +1 -1
  16. package/esm/main/function.js +0 -1
  17. package/esm/main/function.js.map +1 -1
  18. package/esm/main/index.d.ts +5 -0
  19. package/esm/main/index.d.ts.map +1 -1
  20. package/esm/main/index.js +5 -0
  21. package/esm/main/index.js.map +1 -1
  22. package/esm/main/key.d.ts +20 -18
  23. package/esm/main/key.d.ts.map +1 -1
  24. package/esm/main/key.js.map +1 -1
  25. package/esm/main/object.d.ts +57 -32
  26. package/esm/main/object.d.ts.map +1 -1
  27. package/esm/main/object.js.map +1 -1
  28. package/esm/main/tuple.d.ts +30 -6
  29. package/esm/main/tuple.d.ts.map +1 -1
  30. package/esm/main/tuple.js.map +1 -1
  31. package/esm/main/type/compare.d.ts +108 -18
  32. package/esm/main/type/compare.d.ts.map +1 -1
  33. package/esm/main/type/compare.js.map +1 -1
  34. package/esm/main/type/set.d.ts +15 -8
  35. package/esm/main/type/set.d.ts.map +1 -1
  36. package/esm/main/type/set.js.map +1 -1
  37. package/esm/test-utils/compare.d.ts +12 -0
  38. package/esm/test-utils/compare.d.ts.map +1 -1
  39. package/esm/test-utils/compare.js.map +1 -1
  40. package/esm/test-utils/expect.d.ts +63 -8
  41. package/esm/test-utils/expect.d.ts.map +1 -1
  42. package/esm/test-utils/expect.js.map +1 -1
  43. package/esm/test-utils/index.d.ts +5 -0
  44. package/esm/test-utils/index.d.ts.map +1 -1
  45. package/esm/test-utils/index.js +5 -1
  46. package/esm/test-utils/index.js.map +1 -1
  47. package/package.json +1 -1
  48. package/script/main/async.d.ts +9 -1
  49. package/script/main/async.d.ts.map +1 -1
  50. package/script/main/async.js.map +1 -1
  51. package/script/main/boolean.d.ts +43 -19
  52. package/script/main/boolean.d.ts.map +1 -1
  53. package/script/main/boolean.js.map +1 -1
  54. package/script/main/control.d.ts +65 -36
  55. package/script/main/control.d.ts.map +1 -1
  56. package/script/main/control.js.map +1 -1
  57. package/script/main/doc.d.ts +33 -7
  58. package/script/main/doc.d.ts.map +1 -1
  59. package/script/main/doc.js.map +1 -1
  60. package/script/main/function.d.ts +11 -3
  61. package/script/main/function.d.ts.map +1 -1
  62. package/script/main/function.js +0 -1
  63. package/script/main/function.js.map +1 -1
  64. package/script/main/index.d.ts +5 -0
  65. package/script/main/index.d.ts.map +1 -1
  66. package/script/main/index.js +5 -0
  67. package/script/main/index.js.map +1 -1
  68. package/script/main/key.d.ts +20 -18
  69. package/script/main/key.d.ts.map +1 -1
  70. package/script/main/key.js.map +1 -1
  71. package/script/main/object.d.ts +57 -32
  72. package/script/main/object.d.ts.map +1 -1
  73. package/script/main/object.js.map +1 -1
  74. package/script/main/tuple.d.ts +30 -6
  75. package/script/main/tuple.d.ts.map +1 -1
  76. package/script/main/tuple.js.map +1 -1
  77. package/script/main/type/compare.d.ts +108 -18
  78. package/script/main/type/compare.d.ts.map +1 -1
  79. package/script/main/type/compare.js.map +1 -1
  80. package/script/main/type/set.d.ts +15 -8
  81. package/script/main/type/set.d.ts.map +1 -1
  82. package/script/main/type/set.js.map +1 -1
  83. package/script/test-utils/compare.d.ts +12 -0
  84. package/script/test-utils/compare.d.ts.map +1 -1
  85. package/script/test-utils/compare.js.map +1 -1
  86. package/script/test-utils/expect.d.ts +63 -8
  87. package/script/test-utils/expect.d.ts.map +1 -1
  88. package/script/test-utils/expect.js.map +1 -1
  89. package/script/test-utils/index.d.ts +5 -0
  90. package/script/test-utils/index.d.ts.map +1 -1
  91. package/script/test-utils/index.js +5 -1
  92. package/script/test-utils/index.js.map +1 -1
package/esm/main/key.d.ts CHANGED
@@ -9,22 +9,23 @@ import type { Exact } from './type/index.js';
9
9
  * @template ValueType - The base type to match against property values (ignoring undefined from optional properties).
10
10
  *
11
11
  * @example
12
+ * ```ts
13
+ * import { expect } from '@leawind/lay-sing/test-utils'
14
+ *
12
15
  * // Basic usage: match base type (non-optional property)
13
16
  * type A = { a: 1; b: 2; c: 1 };
14
- * type MatchedKeys = KeysOfBaseType<A, 1>; // 'a' | 'c'
17
+ * expect<KeysOfBaseType<A, 1>>().toBe<'a' | 'c'>().success
15
18
  *
16
- * @example
17
19
  * // Key difference: optional property matching (ignores undefined)
18
20
  * type B = { a?: string; b: string };
19
- * type MatchBaseString = KeysOfBaseType<B, string>; // 'a' | 'b' (matches base type of both)
20
- * type MatchWithUndefined = KeysOfBaseType<B, string | undefined>; // never (base type does not include undefined)
21
+ * expect<KeysOfBaseType<B, string>>().toBe<'a' | 'b'>().success // matches base type of both
22
+ * expect<KeysOfBaseType<B, string | undefined>>().toBe<never>().success // base type does not include undefined
21
23
  *
22
- * @example
23
- * // Edge cases: never/any/unknown
24
24
  * type C = { a: never; b: any; c: unknown };
25
- * type MatchNever = KeysOfBaseType<C, never>; // 'a'
26
- * type MatchAny = KeysOfBaseType<C, any>; // 'b'
27
- * type MatchUnknown = KeysOfBaseType<C, unknown>; // 'c'
25
+ * expect<KeysOfBaseType<C, never>>().toBe<'a'>().success
26
+ * expect<KeysOfBaseType<C, any>>().toBe<'b'>().success
27
+ * expect<KeysOfBaseType<C, unknown>>().toBe<'c'>().success
28
+ * ```
28
29
  */
29
30
  export type KeysOfBaseType<Obj, ValueType> = Exclude<{
30
31
  [K in keyof Obj]: Exact<Required<Obj>[K], ValueType> extends true ? K : never;
@@ -39,22 +40,23 @@ export type KeysOfBaseType<Obj, ValueType> = Exclude<{
39
40
  * @template ValueType - The exact type to match against property values (including undefined for optional properties).
40
41
  *
41
42
  * @example
43
+ * ```ts
44
+ * import { expect } from '@leawind/lay-sing/test-utils'
45
+ *
42
46
  * // Basic usage: match exact type (non-optional property)
43
47
  * type A = { a: 1; b: 2; c: 1 };
44
- * type MatchedKeys = KeysOfExactType<A, 1>; // 'a' | 'c'
48
+ * expect<KeysOfExactType<A, 1>>().toBe<'a' | 'c'>().success
45
49
  *
46
- * @example
47
50
  * // Key difference: optional property matching (requires undefined in `ValueType`)
48
51
  * type B = { a?: string };
49
- * type MatchWithUndefined = KeysOfExactType<B, string | undefined>; // 'a' (matches complete type)
50
- * type MatchWithoutUndefined = KeysOfExactType<B, string>; // never (does not match complete type)
52
+ * expect<KeysOfExactType<B, string | undefined>>().toBe<'a'>().success // matches complete type
53
+ * expect<KeysOfExactType<B, string>>().toBe<never>().success // does not match complete type
51
54
  *
52
- * @example
53
- * // Edge cases: never/any/unknown
54
55
  * type C = { a: never; b: any; c: unknown };
55
- * type MatchNever = KeysOfExactType<C, never>; // 'a'
56
- * type MatchAny = KeysOfExactType<C, any>; // 'b'
57
- * type MatchUnknown = KeysOfExactType<C, unknown>; // 'c'
56
+ * expect<KeysOfExactType<C, never>>().toBe<'a'>().success
57
+ * expect<KeysOfExactType<C, any>>().toBe<'b'>().success
58
+ * expect<KeysOfExactType<C, unknown>>().toBe<'c'>().success
59
+ * ```
58
60
  */
59
61
  export type KeysOfExactType<Obj, ValueType> = Exclude<{
60
62
  [K in keyof Obj]: Exact<Obj[K], ValueType> extends true ? K : never;
@@ -1 +1 @@
1
- {"version":3,"file":"key.d.ts","sourceRoot":"","sources":["../../src/main/key.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,cAAc,CAAC,GAAG,EAAE,SAAS,IAAI,OAAO,CAClD;KACG,CAAC,IAAI,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK;CAC9E,CAAC,MAAM,GAAG,CAAC,EACZ,SAAS,CACV,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,eAAe,CAAC,GAAG,EAAE,SAAS,IAAI,OAAO,CACnD;KAAG,CAAC,IAAI,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK;CAAE,CAAC,MAAM,GAAG,CAAC,EAClF,SAAS,CACV,CAAA"}
1
+ {"version":3,"file":"key.d.ts","sourceRoot":"","sources":["../../src/main/key.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,MAAM,cAAc,CAAC,GAAG,EAAE,SAAS,IAAI,OAAO,CAClD;KACG,CAAC,IAAI,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK;CAC9E,CAAC,MAAM,GAAG,CAAC,EACZ,SAAS,CACV,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,MAAM,eAAe,CAAC,GAAG,EAAE,SAAS,IAAI,OAAO,CACnD;KAAG,CAAC,IAAI,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK;CAAE,CAAC,MAAM,GAAG,CAAC,EAClF,SAAS,CACV,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"key.js","sourceRoot":"","sources":["../../src/main/key.ts"],"names":[],"mappings":"","sourcesContent":["import type { Exact } from './type/index.js'\n\n/**\n * Extracts the keys of an object whose **base value type** matches the specified `ValueType` (ignoring undefined from optional properties).\n *\n * This utility matches the underlying/base type of each property (stripping `undefined` added by optional modifiers `?`).\n * For optional properties (e.g., `a?: string`), the type is treated as `string` – no need to include `undefined` in `ValueType` to match.\n *\n * @template Obj - The target object type to extract keys from.\n * @template ValueType - The base type to match against property values (ignoring undefined from optional properties).\n *\n * @example\n * // Basic usage: match base type (non-optional property)\n * type A = { a: 1; b: 2; c: 1 };\n * type MatchedKeys = KeysOfBaseType<A, 1>; // 'a' | 'c'\n *\n * @example\n * // Key difference: optional property matching (ignores undefined)\n * type B = { a?: string; b: string };\n * type MatchBaseString = KeysOfBaseType<B, string>; // 'a' | 'b' (matches base type of both)\n * type MatchWithUndefined = KeysOfBaseType<B, string | undefined>; // never (base type does not include undefined)\n *\n * @example\n * // Edge cases: never/any/unknown\n * type C = { a: never; b: any; c: unknown };\n * type MatchNever = KeysOfBaseType<C, never>; // 'a'\n * type MatchAny = KeysOfBaseType<C, any>; // 'b'\n * type MatchUnknown = KeysOfBaseType<C, unknown>; // 'c'\n */\nexport type KeysOfBaseType<Obj, ValueType> = Exclude<\n {\n [K in keyof Obj]: Exact<Required<Obj>[K], ValueType> extends true ? K : never\n }[keyof Obj],\n undefined\n>\n\n/**\n * Extracts the keys of an object whose **complete value type** exactly matches the specified `ValueType` (including undefined for optional properties).\n *\n * This utility strictly matches the full type of each property (including `undefined` added by optional modifiers `?`).\n * For optional properties (e.g., `a?: string`), the type is treated as `string | undefined` – to match, `ValueType` must include `undefined`.\n *\n * @template Obj - The target object type to extract keys from.\n * @template ValueType - The exact type to match against property values (including undefined for optional properties).\n *\n * @example\n * // Basic usage: match exact type (non-optional property)\n * type A = { a: 1; b: 2; c: 1 };\n * type MatchedKeys = KeysOfExactType<A, 1>; // 'a' | 'c'\n *\n * @example\n * // Key difference: optional property matching (requires undefined in `ValueType`)\n * type B = { a?: string };\n * type MatchWithUndefined = KeysOfExactType<B, string | undefined>; // 'a' (matches complete type)\n * type MatchWithoutUndefined = KeysOfExactType<B, string>; // never (does not match complete type)\n *\n * @example\n * // Edge cases: never/any/unknown\n * type C = { a: never; b: any; c: unknown };\n * type MatchNever = KeysOfExactType<C, never>; // 'a'\n * type MatchAny = KeysOfExactType<C, any>; // 'b'\n * type MatchUnknown = KeysOfExactType<C, unknown>; // 'c'\n */\nexport type KeysOfExactType<Obj, ValueType> = Exclude<\n { [K in keyof Obj]: Exact<Obj[K], ValueType> extends true ? K : never }[keyof Obj],\n undefined\n>\n"]}
1
+ {"version":3,"file":"key.js","sourceRoot":"","sources":["../../src/main/key.ts"],"names":[],"mappings":"","sourcesContent":["import type { Exact } from './type/index.js'\n\n/**\n * Extracts the keys of an object whose **base value type** matches the specified `ValueType` (ignoring undefined from optional properties).\n *\n * This utility matches the underlying/base type of each property (stripping `undefined` added by optional modifiers `?`).\n * For optional properties (e.g., `a?: string`), the type is treated as `string` – no need to include `undefined` in `ValueType` to match.\n *\n * @template Obj - The target object type to extract keys from.\n * @template ValueType - The base type to match against property values (ignoring undefined from optional properties).\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * // Basic usage: match base type (non-optional property)\n * type A = { a: 1; b: 2; c: 1 };\n * expect<KeysOfBaseType<A, 1>>().toBe<'a' | 'c'>().success\n *\n * // Key difference: optional property matching (ignores undefined)\n * type B = { a?: string; b: string };\n * expect<KeysOfBaseType<B, string>>().toBe<'a' | 'b'>().success // matches base type of both\n * expect<KeysOfBaseType<B, string | undefined>>().toBe<never>().success // base type does not include undefined\n *\n * type C = { a: never; b: any; c: unknown };\n * expect<KeysOfBaseType<C, never>>().toBe<'a'>().success\n * expect<KeysOfBaseType<C, any>>().toBe<'b'>().success\n * expect<KeysOfBaseType<C, unknown>>().toBe<'c'>().success\n * ```\n */\nexport type KeysOfBaseType<Obj, ValueType> = Exclude<\n {\n [K in keyof Obj]: Exact<Required<Obj>[K], ValueType> extends true ? K : never\n }[keyof Obj],\n undefined\n>\n\n/**\n * Extracts the keys of an object whose **complete value type** exactly matches the specified `ValueType` (including undefined for optional properties).\n *\n * This utility strictly matches the full type of each property (including `undefined` added by optional modifiers `?`).\n * For optional properties (e.g., `a?: string`), the type is treated as `string | undefined` – to match, `ValueType` must include `undefined`.\n *\n * @template Obj - The target object type to extract keys from.\n * @template ValueType - The exact type to match against property values (including undefined for optional properties).\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * // Basic usage: match exact type (non-optional property)\n * type A = { a: 1; b: 2; c: 1 };\n * expect<KeysOfExactType<A, 1>>().toBe<'a' | 'c'>().success\n *\n * // Key difference: optional property matching (requires undefined in `ValueType`)\n * type B = { a?: string };\n * expect<KeysOfExactType<B, string | undefined>>().toBe<'a'>().success // matches complete type\n * expect<KeysOfExactType<B, string>>().toBe<never>().success // does not match complete type\n *\n * type C = { a: never; b: any; c: unknown };\n * expect<KeysOfExactType<C, never>>().toBe<'a'>().success\n * expect<KeysOfExactType<C, any>>().toBe<'b'>().success\n * expect<KeysOfExactType<C, unknown>>().toBe<'c'>().success\n * ```\n */\nexport type KeysOfExactType<Obj, ValueType> = Exclude<\n { [K in keyof Obj]: Exact<Obj[K], ValueType> extends true ? K : never }[keyof Obj],\n undefined\n>\n"]}
@@ -1,20 +1,39 @@
1
1
  import type { KeysOfExactType } from './key.js';
2
2
  /**
3
- * Access a property with key `K` in object `T`, with a fallback `E` if the property doesn't exist
3
+ * Get property type from object, with fallback for missing keys.
4
+ *
5
+ * @template Obj - The object type to access
6
+ * @template K - The key to access in the object
7
+ * @template E - The fallback type if the key doesn't exist (defaults to `never`)
8
+ *
9
+ * @returns `Obj[K]` if key exists, otherwise `E`.
4
10
  *
5
11
  * @example
6
12
  * ```ts
7
- * type Result = Access<{ a: string }, 'a'> // string
8
- * type Missing = Access<{ a: string }, 'x', 'default'> // 'default'
13
+ * import { expect } from '@leawind/lay-sing/test-utils'
14
+ *
15
+ * type User = { name: string; age?: number };
16
+ *
17
+ * expect<Access<User, 'name'>>().toBe<string>().success
18
+ * expect<Access<User, 'age'>>().toBe<number | undefined>().success
19
+ * expect<Access<User, 'email', 'none'>>().toBe<'none'>().success
9
20
  * ```
10
21
  */
11
22
  export type Access<Obj, K extends PropertyKey, E = never> = K extends keyof Obj ? Obj[K] : E;
12
23
  /**
13
- * Inverse of `Access`
24
+ * Inverse of `Access` - gets keys from an object that have values of a specific type
25
+ *
26
+ * @template T - The object type to inspect
27
+ * @template V - The value type to match against
28
+ * @template E - The fallback type if no keys match (defaults to `never`)
14
29
  *
15
30
  * @example
16
31
  * ```ts
17
- * type Result = InverseAccess<{ a: string }, string> // 'a'
32
+ * import { expect } from '@leawind/lay-sing/test-utils'
33
+ *
34
+ * expect<InverseAccess<{ a: string }, string>>().toBe<'a'>().success
35
+ * expect<InverseAccess<{ a: string; b: string }, string>>().toBe<'a' | 'b'>().success
36
+ * expect<InverseAccess<{ a: string }, number>>().toBe<never>().success
18
37
  * ```
19
38
  */
20
39
  export type InverseAccess<T, V, E = never> = {
@@ -23,9 +42,14 @@ export type InverseAccess<T, V, E = never> = {
23
42
  /**
24
43
  * Recursively makes all properties of `T` optional
25
44
  *
45
+ * @template T - The object type to make deep partial
46
+ *
26
47
  * @example
27
48
  * ```ts
28
- * type Result = DeepPartial<{ a: string; nested: { b: number } }> // { a?: string; nested?: { b?: number } }
49
+ * import { expect } from '@leawind/lay-sing/test-utils'
50
+ *
51
+ * type Result = DeepPartial<{ a: string; nested: { b: number } }>
52
+ * expect<Result>().toBe<{ a?: string; nested?: { b?: number } }>().success
29
53
  * ```
30
54
  */
31
55
  export type DeepPartial<T> = {
@@ -34,22 +58,20 @@ export type DeepPartial<T> = {
34
58
  /**
35
59
  * Recursively makes all properties of `T` required
36
60
  *
61
+ * @template T - The object type to make deep required
62
+ *
37
63
  * @example
38
64
  * ```ts
39
- * type Result = DeepRequire<{ a?: string; nested?: { b?: number } }>
40
- * // { a: string; nested: { b: number } }
65
+ * import { expect } from '@leawind/lay-sing/test-utils'
66
+ *
67
+ * expect<DeepRequire<{ _?: { _?: 1 } }>>().toBe<{ _: { _: 1 } }>().success
41
68
  * ```
42
69
  */
43
70
  export type DeepRequire<T> = {
44
- [P in keyof T]-?: T[P] extends object ? DeepRequire<T[P]> : T[P];
71
+ [K in keyof T]-?: T[K] extends object | undefined ? DeepRequire<NonNullable<T[K]>> : T[K];
45
72
  };
46
73
  /**
47
- * A non-distributive conditional type that checks if the entire type `T`
48
- * (treated as a single entity) is assignable to type `U`.
49
- *
50
- * Unlike the built-in distributive version (`Extract<T, U>`), this type wraps `T` and `U` in tuples to
51
- * prevent distribution over union types. The entire type `T` must satisfy
52
- * the constraint `U` for the check to pass.
74
+ * **⚠️Important:** parameter `T` and `U` are not distributive. When they are union type, it treats them as a single entity.
53
75
  *
54
76
  * @template T - The type to test (not distributed over unions)
55
77
  * @template U - The constraint type to test against
@@ -57,38 +79,41 @@ export type DeepRequire<T> = {
57
79
  * @example
58
80
  *
59
81
  * ```ts
60
- * // Non-distributive check - entire type must satisfy constraint
61
- * type T1 = string | number;
62
- * type Test1 = AssertExtends<T1, string | number>; // string | number
63
- * type Test2 = AssertExtends<T1, string>; // never
64
- *
65
- * // Compare distributive vs non-distributive behavior
66
- * type Union1 = 'a' | 'b'
67
- * type Dist = Extract<Union1, string> // 'a' | 'b'
68
- * type NonDist = AssertExtends<Union1, string> // 'a' | 'b'
69
- *
70
- * type Union2 = 'a' | 1
71
- * type Dist2 = Extract<Union2, string> // 'a'
72
- * type NonDist2 = AssertExtends<Union2, string> // never
82
+ * import { expect } from '@leawind/lay-sing/test-utils'
83
+ *
84
+ * expect<AssertExtends<string, number>>().toBeNever
85
+ * expect<AssertExtends<1 | 2, 1>>().toBeNever
86
+ * expect<AssertExtends<1, 1 | 2>>().toBe<1>().success
73
87
  * ```
74
88
  */
75
89
  export type AssertExtends<T, U> = [T] extends [U] ? T : never;
76
90
  /**
77
- * Safely picks keys `K` from type T, excluding non-existent keys
91
+ * Safely picks keys `Key` from type `Obj`, excluding non-existent keys
92
+ *
93
+ * @template Obj - The object type to pick keys from
94
+ * @template Key - The keys to pick from the object
78
95
  *
79
96
  * @example
80
97
  * ```ts
81
- * type Result = SafePick<{ a: string; b: number }, 'a' | 'c'> // { a: string }
98
+ * import { expect } from '@leawind/lay-sing/test-utils'
99
+ *
100
+ * type Result = SafePick<{ a: string; b: number }, 'a' | 'c'>
101
+ * expect<Result>().toBe<{ a: string }>().success
82
102
  * ```
83
103
  */
84
104
  export type SafePick<Obj, Key> = Pick<Obj, Key & keyof Obj>;
85
105
  /**
86
- * Picks properties from `T` that have values of type U
106
+ * Picks properties from `T` that have values of type `U`
107
+ *
108
+ * @template T - The object type to pick properties from
109
+ * @template U - The value type to match against
87
110
  *
88
111
  * @example
89
112
  * ```ts
113
+ * import { expect } from '@leawind/lay-sing/test-utils'
90
114
  * type A = { a: string; b: number; c: string }
91
- * type Strings = PropsOfType<A, string> // { a: string; c: string }
115
+ * type Strings = PropsOfBaseType<A, string> // { a: string; c: string }
116
+ * expect<PropsOfBaseType<A, string>>().toBe<{ a: string; c: string }>()
92
117
  * ```
93
118
  */
94
119
  export type PropsOfBaseType<T, U> = Pick<T, KeysOfExactType<Required<T>, U>>;
@@ -1 +1 @@
1
- {"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../../src/main/object.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C;;;;;;;;GAQG;AACH,MAAM,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC,SAAS,WAAW,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,SAAS,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;AAE5F;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;CAAE,CAAC,MAAM,CAAC,CAAC,CAAA;AAEhG;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAChE,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACjE,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAE7D;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,CAAC,CAAA;AAE3D;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../../src/main/object.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC,SAAS,WAAW,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,SAAS,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;AAE5F;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;CAAE,CAAC,MAAM,CAAC,CAAC,CAAA;AAEhG;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAChE,CAAA;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAC1F,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAE7D;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,CAAC,CAAA;AAE3D;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"object.js","sourceRoot":"","sources":["../../src/main/object.ts"],"names":[],"mappings":"","sourcesContent":["import type { KeysOfExactType } from './key.js'\n\n/**\n * Access a property with key `K` in object `T`, with a fallback `E` if the property doesn't exist\n *\n * @example\n * ```ts\n * type Result = Access<{ a: string }, 'a'> // string\n * type Missing = Access<{ a: string }, 'x', 'default'> // 'default'\n * ```\n */\nexport type Access<Obj, K extends PropertyKey, E = never> = K extends keyof Obj ? Obj[K] : E\n\n/**\n * Inverse of `Access`\n *\n * @example\n * ```ts\n * type Result = InverseAccess<{ a: string }, string> // 'a'\n * ```\n */\nexport type InverseAccess<T, V, E = never> = { [K in keyof T]: T[K] extends V ? K : E }[keyof T]\n\n/**\n * Recursively makes all properties of `T` optional\n *\n * @example\n * ```ts\n * type Result = DeepPartial<{ a: string; nested: { b: number } }> // { a?: string; nested?: { b?: number } }\n * ```\n */\nexport type DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]\n}\n\n/**\n * Recursively makes all properties of `T` required\n *\n * @example\n * ```ts\n * type Result = DeepRequire<{ a?: string; nested?: { b?: number } }>\n * // { a: string; nested: { b: number } }\n * ```\n */\nexport type DeepRequire<T> = {\n [P in keyof T]-?: T[P] extends object ? DeepRequire<T[P]> : T[P]\n}\n\n/**\n * A non-distributive conditional type that checks if the entire type `T`\n * (treated as a single entity) is assignable to type `U`.\n *\n * Unlike the built-in distributive version (`Extract<T, U>`), this type wraps `T` and `U` in tuples to\n * prevent distribution over union types. The entire type `T` must satisfy\n * the constraint `U` for the check to pass.\n *\n * @template T - The type to test (not distributed over unions)\n * @template U - The constraint type to test against\n *\n * @example\n *\n * ```ts\n * // Non-distributive check - entire type must satisfy constraint\n * type T1 = string | number;\n * type Test1 = AssertExtends<T1, string | number>; // string | number\n * type Test2 = AssertExtends<T1, string>; // never\n *\n * // Compare distributive vs non-distributive behavior\n * type Union1 = 'a' | 'b'\n * type Dist = Extract<Union1, string> // 'a' | 'b'\n * type NonDist = AssertExtends<Union1, string> // 'a' | 'b'\n *\n * type Union2 = 'a' | 1\n * type Dist2 = Extract<Union2, string> // 'a'\n * type NonDist2 = AssertExtends<Union2, string> // never\n * ```\n */\nexport type AssertExtends<T, U> = [T] extends [U] ? T : never\n\n/**\n * Safely picks keys `K` from type T, excluding non-existent keys\n *\n * @example\n * ```ts\n * type Result = SafePick<{ a: string; b: number }, 'a' | 'c'> // { a: string }\n * ```\n */\nexport type SafePick<Obj, Key> = Pick<Obj, Key & keyof Obj>\n\n/**\n * Picks properties from `T` that have values of type U\n *\n * @example\n * ```ts\n * type A = { a: string; b: number; c: string }\n * type Strings = PropsOfType<A, string> // { a: string; c: string }\n * ```\n */\nexport type PropsOfBaseType<T, U> = Pick<T, KeysOfExactType<Required<T>, U>>\n"]}
1
+ {"version":3,"file":"object.js","sourceRoot":"","sources":["../../src/main/object.ts"],"names":[],"mappings":"","sourcesContent":["import type { KeysOfExactType } from './key.js'\n\n/**\n * Get property type from object, with fallback for missing keys.\n *\n * @template Obj - The object type to access\n * @template K - The key to access in the object\n * @template E - The fallback type if the key doesn't exist (defaults to `never`)\n *\n * @returns `Obj[K]` if key exists, otherwise `E`.\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * type User = { name: string; age?: number };\n *\n * expect<Access<User, 'name'>>().toBe<string>().success\n * expect<Access<User, 'age'>>().toBe<number | undefined>().success\n * expect<Access<User, 'email', 'none'>>().toBe<'none'>().success\n * ```\n */\nexport type Access<Obj, K extends PropertyKey, E = never> = K extends keyof Obj ? Obj[K] : E\n\n/**\n * Inverse of `Access` - gets keys from an object that have values of a specific type\n *\n * @template T - The object type to inspect\n * @template V - The value type to match against\n * @template E - The fallback type if no keys match (defaults to `never`)\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * expect<InverseAccess<{ a: string }, string>>().toBe<'a'>().success\n * expect<InverseAccess<{ a: string; b: string }, string>>().toBe<'a' | 'b'>().success\n * expect<InverseAccess<{ a: string }, number>>().toBe<never>().success\n * ```\n */\nexport type InverseAccess<T, V, E = never> = { [K in keyof T]: T[K] extends V ? K : E }[keyof T]\n\n/**\n * Recursively makes all properties of `T` optional\n *\n * @template T - The object type to make deep partial\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * type Result = DeepPartial<{ a: string; nested: { b: number } }>\n * expect<Result>().toBe<{ a?: string; nested?: { b?: number } }>().success\n * ```\n */\nexport type DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]\n}\n\n/**\n * Recursively makes all properties of `T` required\n *\n * @template T - The object type to make deep required\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * expect<DeepRequire<{ _?: { _?: 1 } }>>().toBe<{ _: { _: 1 } }>().success\n * ```\n */\nexport type DeepRequire<T> = {\n [K in keyof T]-?: T[K] extends object | undefined ? DeepRequire<NonNullable<T[K]>> : T[K]\n}\n\n/**\n * **⚠️Important:** parameter `T` and `U` are not distributive. When they are union type, it treats them as a single entity.\n *\n * @template T - The type to test (not distributed over unions)\n * @template U - The constraint type to test against\n *\n * @example\n *\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * expect<AssertExtends<string, number>>().toBeNever\n * expect<AssertExtends<1 | 2, 1>>().toBeNever\n * expect<AssertExtends<1, 1 | 2>>().toBe<1>().success\n * ```\n */\nexport type AssertExtends<T, U> = [T] extends [U] ? T : never\n\n/**\n * Safely picks keys `Key` from type `Obj`, excluding non-existent keys\n *\n * @template Obj - The object type to pick keys from\n * @template Key - The keys to pick from the object\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * type Result = SafePick<{ a: string; b: number }, 'a' | 'c'>\n * expect<Result>().toBe<{ a: string }>().success\n * ```\n */\nexport type SafePick<Obj, Key> = Pick<Obj, Key & keyof Obj>\n\n/**\n * Picks properties from `T` that have values of type `U`\n *\n * @template T - The object type to pick properties from\n * @template U - The value type to match against\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n * type A = { a: string; b: number; c: string }\n * type Strings = PropsOfBaseType<A, string> // { a: string; c: string }\n * expect<PropsOfBaseType<A, string>>().toBe<{ a: string; c: string }>()\n * ```\n */\nexport type PropsOfBaseType<T, U> = Pick<T, KeysOfExactType<Required<T>, U>>\n"]}
@@ -2,38 +2,62 @@ import type { Exact } from './type/compare.js';
2
2
  /**
3
3
  * Concatenates two tuples into a single tuple type
4
4
  *
5
+ * @template Left - The first tuple type to concatenate
6
+ * @template Right - The second tuple type to concatenate
7
+ *
5
8
  * @example
6
9
  * ```ts
7
- * type Result = ConcatTuple<[1, 2], [3, 4]> // [1, 2, 3, 4]
10
+ * import { expect } from '@leawind/lay-sing/test-utils'
11
+ *
12
+ * expect<ConcatTuple<[1, 2], [3, 4]>>().toBe<[1, 2, 3, 4]>().success
8
13
  * ```
9
14
  */
10
15
  export type ConcatTuple<Left extends readonly unknown[], Right extends readonly unknown[]> = Left extends readonly unknown[] ? (Right extends readonly unknown[] ? [...Left, ...Right] : never) : never;
11
16
  /**
12
17
  * Checks whether a tuple includes a specific element type
13
18
  *
19
+ * @template Tuple - The tuple type to check
20
+ * @template Element - The element type to look for
21
+ * @template Yes - The result if the element is found (defaults to `true`)
22
+ * @template No - The result if the element is not found (defaults to `false`)
23
+ *
14
24
  * @example
15
25
  * ```ts
16
- * type HasTwo = IfTupleIncludes<[1, 2, 3], 2> // true
17
- * type HasFour = IfTupleIncludes<[1, 2, 3], 4> // false
26
+ * import { expect } from '@leawind/lay-sing/test-utils'
27
+ *
28
+ * expect<IfTupleIncludes<[1, 2, 3], 2>>().toBeTrue
29
+ * expect<IfTupleIncludes<[1, 2, 3], 4>>().toBeFalse
30
+ * expect<IfTupleIncludes<[1, 2, 1], 1>>().toBeTrue
18
31
  * ```
19
32
  */
20
33
  export type IfTupleIncludes<Tuple extends readonly unknown[], Element, Yes = true, No = false> = Exact<Tuple, any> extends true ? never : Tuple extends readonly [infer First, ...infer Rest] ? (Exact<Element, First> extends true ? Yes : IfTupleIncludes<Rest, Element, Yes, No>) : No;
21
34
  /**
22
35
  * Appends an element to a tuple only if it doesn't already exist in the tuple
23
36
  *
37
+ * @template Tuple - The tuple type to append to
38
+ * @template Element - The element type to append
39
+ *
24
40
  * @example
25
41
  * ```ts
26
- * type Result1 = AppendUnique<[1, 2, 3], 4> // [1, 2, 3, 4]
27
- * type Result2 = AppendUnique<[1, 2, 3], 2> // [1, 2, 3]
42
+ * import { expect } from '@leawind/lay-sing/test-utils'
43
+ *
44
+ * expect<AppendUnique<[1, 2, 3], 4>>().toBe<[1, 2, 3, 4]>().success
45
+ * expect<AppendUnique<[1, 2, 3], 2>>().toBe<[1, 2, 3]>().success
28
46
  * ```
29
47
  */
30
48
  export type AppendUnique<Tuple extends readonly unknown[], Element> = IfTupleIncludes<Tuple, Element> extends true ? Tuple : [...Tuple, Element];
31
49
  /**
32
50
  * Concatenates two tuples while ensuring uniqueness of elements
33
51
  *
52
+ * @template Left - The first tuple type to concatenate
53
+ * @template Right - The second tuple type to concatenate
54
+ * @template R - The intermediate result tuple type (defaults to `Left`)
55
+ *
34
56
  * @example
35
57
  * ```ts
36
- * type Result = ConcatUniqueTuple<[1, 2, 3], [2, 3, 4]> // [1, 2, 3, 4]
58
+ * import { expect } from '@leawind/lay-sing/test-utils'
59
+ *
60
+ * expect<ConcatUniqueTuple<[1, 2, 3], [2, 3, 4]>>().toBe<[1, 2, 3, 4]>().success
37
61
  * ```
38
62
  */
39
63
  export type ConcatUniqueTuple<Left extends readonly unknown[], Right extends readonly unknown[], R extends readonly unknown[] = Left> = Right extends readonly [infer First, ...infer Rest] ? ConcatUniqueTuple<Left, Rest, AppendUnique<R, First>> : R;
@@ -1 +1 @@
1
- {"version":3,"file":"tuple.d.ts","sourceRoot":"","sources":["../../src/main/tuple.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAE9C;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,CACrB,IAAI,SAAS,SAAS,OAAO,EAAE,EAC/B,KAAK,SAAS,SAAS,OAAO,EAAE,IAC9B,IAAI,SAAS,SAAS,OAAO,EAAE,GAAG,CAAC,KAAK,SAAS,SAAS,OAAO,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAA;AAE9G;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,CACzB,KAAK,SAAS,SAAS,OAAO,EAAE,EAChC,OAAO,EACP,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,KAAK,GACtC,KAAK,SAAS,SAAS,CAAC,MAAM,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,GACjD,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,IAAI,GAAG,GAAG,GAAG,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,GACtF,EAAE,CAAA;AAEN;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,CACtB,KAAK,SAAS,SAAS,OAAO,EAAE,EAChC,OAAO,IACL,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,IAAI,GAAG,KAAK,GAAG,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,CAAA;AAE9E;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,CAC3B,IAAI,SAAS,SAAS,OAAO,EAAE,EAC/B,KAAK,SAAS,SAAS,OAAO,EAAE,EAChC,CAAC,SAAS,SAAS,OAAO,EAAE,GAAG,IAAI,IACjC,KAAK,SAAS,SAAS,CAAC,MAAM,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAA"}
1
+ {"version":3,"file":"tuple.d.ts","sourceRoot":"","sources":["../../src/main/tuple.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAE9C;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,CACrB,IAAI,SAAS,SAAS,OAAO,EAAE,EAC/B,KAAK,SAAS,SAAS,OAAO,EAAE,IAC9B,IAAI,SAAS,SAAS,OAAO,EAAE,GAAG,CAAC,KAAK,SAAS,SAAS,OAAO,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAA;AAE9G;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,eAAe,CACzB,KAAK,SAAS,SAAS,OAAO,EAAE,EAChC,OAAO,EACP,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,KAAK,GACtC,KAAK,SAAS,SAAS,CAAC,MAAM,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,GACjD,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,IAAI,GAAG,GAAG,GAAG,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,GACtF,EAAE,CAAA;AAEN;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,YAAY,CACtB,KAAK,SAAS,SAAS,OAAO,EAAE,EAChC,OAAO,IACL,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,IAAI,GAAG,KAAK,GAAG,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,CAAA;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,iBAAiB,CAC3B,IAAI,SAAS,SAAS,OAAO,EAAE,EAC/B,KAAK,SAAS,SAAS,OAAO,EAAE,EAChC,CAAC,SAAS,SAAS,OAAO,EAAE,GAAG,IAAI,IACjC,KAAK,SAAS,SAAS,CAAC,MAAM,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"tuple.js","sourceRoot":"","sources":["../../src/main/tuple.ts"],"names":[],"mappings":"","sourcesContent":["// deno-lint-ignore-file no-explicit-any\nimport type { Exact } from './type/compare.js'\n\n/**\n * Concatenates two tuples into a single tuple type\n *\n * @example\n * ```ts\n * type Result = ConcatTuple<[1, 2], [3, 4]> // [1, 2, 3, 4]\n * ```\n */\nexport type ConcatTuple<\n Left extends readonly unknown[],\n Right extends readonly unknown[],\n> = Left extends readonly unknown[] ? (Right extends readonly unknown[] ? [...Left, ...Right] : never) : never\n\n/**\n * Checks whether a tuple includes a specific element type\n *\n * @example\n * ```ts\n * type HasTwo = IfTupleIncludes<[1, 2, 3], 2> // true\n * type HasFour = IfTupleIncludes<[1, 2, 3], 4> // false\n * ```\n */\nexport type IfTupleIncludes<\n Tuple extends readonly unknown[],\n Element,\n Yes = true,\n No = false,\n> = Exact<Tuple, any> extends true ? never\n : Tuple extends readonly [infer First, ...infer Rest]\n ? (Exact<Element, First> extends true ? Yes : IfTupleIncludes<Rest, Element, Yes, No>)\n : No\n\n/**\n * Appends an element to a tuple only if it doesn't already exist in the tuple\n *\n * @example\n * ```ts\n * type Result1 = AppendUnique<[1, 2, 3], 4> // [1, 2, 3, 4]\n * type Result2 = AppendUnique<[1, 2, 3], 2> // [1, 2, 3]\n * ```\n */\nexport type AppendUnique<\n Tuple extends readonly unknown[],\n Element,\n> = IfTupleIncludes<Tuple, Element> extends true ? Tuple : [...Tuple, Element]\n\n/**\n * Concatenates two tuples while ensuring uniqueness of elements\n *\n * @example\n * ```ts\n * type Result = ConcatUniqueTuple<[1, 2, 3], [2, 3, 4]> // [1, 2, 3, 4]\n * ```\n */\nexport type ConcatUniqueTuple<\n Left extends readonly unknown[],\n Right extends readonly unknown[],\n R extends readonly unknown[] = Left,\n> = Right extends readonly [infer First, ...infer Rest] ? ConcatUniqueTuple<Left, Rest, AppendUnique<R, First>> : R\n"]}
1
+ {"version":3,"file":"tuple.js","sourceRoot":"","sources":["../../src/main/tuple.ts"],"names":[],"mappings":"","sourcesContent":["import type { Exact } from './type/compare.js'\n\n/**\n * Concatenates two tuples into a single tuple type\n *\n * @template Left - The first tuple type to concatenate\n * @template Right - The second tuple type to concatenate\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * expect<ConcatTuple<[1, 2], [3, 4]>>().toBe<[1, 2, 3, 4]>().success\n * ```\n */\nexport type ConcatTuple<\n Left extends readonly unknown[],\n Right extends readonly unknown[],\n> = Left extends readonly unknown[] ? (Right extends readonly unknown[] ? [...Left, ...Right] : never) : never\n\n/**\n * Checks whether a tuple includes a specific element type\n *\n * @template Tuple - The tuple type to check\n * @template Element - The element type to look for\n * @template Yes - The result if the element is found (defaults to `true`)\n * @template No - The result if the element is not found (defaults to `false`)\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * expect<IfTupleIncludes<[1, 2, 3], 2>>().toBeTrue\n * expect<IfTupleIncludes<[1, 2, 3], 4>>().toBeFalse\n * expect<IfTupleIncludes<[1, 2, 1], 1>>().toBeTrue\n * ```\n */\nexport type IfTupleIncludes<\n Tuple extends readonly unknown[],\n Element,\n Yes = true,\n No = false,\n> = Exact<Tuple, any> extends true ? never\n : Tuple extends readonly [infer First, ...infer Rest]\n ? (Exact<Element, First> extends true ? Yes : IfTupleIncludes<Rest, Element, Yes, No>)\n : No\n\n/**\n * Appends an element to a tuple only if it doesn't already exist in the tuple\n *\n * @template Tuple - The tuple type to append to\n * @template Element - The element type to append\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * expect<AppendUnique<[1, 2, 3], 4>>().toBe<[1, 2, 3, 4]>().success\n * expect<AppendUnique<[1, 2, 3], 2>>().toBe<[1, 2, 3]>().success\n * ```\n */\nexport type AppendUnique<\n Tuple extends readonly unknown[],\n Element,\n> = IfTupleIncludes<Tuple, Element> extends true ? Tuple : [...Tuple, Element]\n\n/**\n * Concatenates two tuples while ensuring uniqueness of elements\n *\n * @template Left - The first tuple type to concatenate\n * @template Right - The second tuple type to concatenate\n * @template R - The intermediate result tuple type (defaults to `Left`)\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * expect<ConcatUniqueTuple<[1, 2, 3], [2, 3, 4]>>().toBe<[1, 2, 3, 4]>().success\n * ```\n */\nexport type ConcatUniqueTuple<\n Left extends readonly unknown[],\n Right extends readonly unknown[],\n R extends readonly unknown[] = Left,\n> = Right extends readonly [infer First, ...infer Rest] ? ConcatUniqueTuple<Left, Rest, AppendUnique<R, First>> : R\n"]}
@@ -1,13 +1,31 @@
1
1
  /**
2
2
  * Checks whether two types are exactly the same.
3
3
  *
4
- * This performs a structural equality comparison between `A` and `B`,
5
- * rather than a one-way assignability check.
4
+ * **⚠️Important:** parameter `A` and `B` are not distributive. When they are union type, it does not check each member separately.
5
+ *
6
+ * @template A - The first type to compare
7
+ * @template B - The second type to compare
8
+ * @template Yes - The result if types are exactly the same (defaults to `true`)
9
+ * @template No - The result if types are not exactly the same (defaults to `false`)
6
10
  *
7
11
  * ### Result
8
12
  *
9
- * - `true`: `A` and `B` are identical types
10
- * - `false`: Otherwise
13
+ * - `Yes`: `A` and `B` are exactly the same
14
+ * - `No`: Otherwise
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { expect } from '@leawind/lay-sing/test-utils'
19
+ *
20
+ * expect<Exact<string, string>>().toBeTrue
21
+ * expect<Exact<never, never>>().toBeTrue
22
+ * expect<Exact<any, any>>().toBeTrue
23
+ *
24
+ * expect<Exact<{ a: 3 }, { a?: 3 }>>().toBeFalse
25
+ * expect<Exact<1 | 2, 1>>().toBeFalse
26
+ * expect<Exact<1, number>>().toBeFalse
27
+ * expect<Exact<() => void, () => undefined>>().toBeFalse
28
+ * ```
11
29
  */
12
30
  export type Exact<A, B, Yes = true, No = false> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? Yes : No;
13
31
  /**
@@ -15,24 +33,34 @@ export type Exact<A, B, Yes = true, No = false> = (<T>() => T extends A ? 1 : 2)
15
33
  *
16
34
  * This is the logical negation of `Exact<A, B>`.
17
35
  *
18
- * ### Result
19
- *
20
- * - `true`: `A` and `B` are not identical
21
- * - `false`: `A` and `B` are exactly the same type
36
+ * @template A - The first type to compare
37
+ * @template B - The second type to compare
38
+ * @template Yes - The result if types are not exactly the same (defaults to `true`)
39
+ * @template No - The result if types are exactly the same (defaults to `false`)
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * type T1 = NotExact<number, string> // true
44
+ * type T2 = NotExact<1, number> // true
45
+ * type F1 = NotExact<number, number> // false
46
+ * type F2 = NotExact<1, 1> // false
47
+ * ```
22
48
  */
23
49
  export type NotExact<A, B, Yes = true, No = false> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? No : Yes;
24
50
  /**
25
51
  * Checks whether type `A` extends type `B`.
26
52
  *
27
- * This is a non-distributive version of `extends`, ensuring
28
- * the result is always a concrete boolean literal.
53
+ * **⚠️Important:** parameter `A` and `B` are not distributive. When they are union type, it treats them as a single entity.
29
54
  *
30
- * ### Result
55
+ * @template A - The type to check if it extends another type
56
+ * @template B - The type to check if `A` extends
57
+ * @template Yes - The result if `A` extends `B` (defaults to `true`)
58
+ * @template No - The result if `A` does not extend `B` (defaults to `false`)
31
59
  *
32
- * - `true`: `A` is assignable to `B`
33
- * - `false`: Otherwise
60
+ * ### Result
34
61
  *
35
- * **Note:** the result will never be `boolean`.
62
+ * - `Yes`: `A` is assignable to `B`
63
+ * - `No`: Otherwise
36
64
  */
37
65
  export type Extends<A, B, Yes = true, No = false> = [A] extends [B] ? Yes : No;
38
66
  /**
@@ -42,16 +70,47 @@ export type Extends<A, B, Yes = true, No = false> = [A] extends [B] ? Yes : No;
42
70
  * - `A` extends `B`
43
71
  * - `A` is not exactly the same type as `B`
44
72
  *
73
+ * @template A - The type to check if it is a proper subtype
74
+ * @template B - The type to check against
75
+ * @template Yes - The result if `A` is a proper subtype of `B` (defaults to `true`)
76
+ * @template No - The result if `A` is not a proper subtype of `B` (defaults to `false`)
77
+ *
78
+ * ### Result
79
+ *
80
+ * - `Yes`: `A` is a proper subtype of `B`
81
+ * - `No`: Otherwise
82
+ *
45
83
  * **Note:** the result will never be `boolean`.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * type T1 = ProperExtend<true, boolean> // true
88
+ * type T2 = ProperExtend<1, number> // true
89
+ * type F1 = ProperExtend<boolean, boolean> // false
90
+ * type F2 = ProperExtend<number, string> // false
91
+ * ```
46
92
  */
47
93
  export type ProperExtend<A, B, Yes = true, No = false> = [A] extends [B] ? Exact<A, B> extends false ? Yes : No : No;
48
94
  /**
49
95
  * Checks whether two types have any overlapping members.
50
96
  *
97
+ * @template A - The first type to check for overlap
98
+ * @template B - The second type to check for overlap
99
+ * @template Yes - The result if types overlap (defaults to `true`)
100
+ * @template No - The result if types do not overlap (defaults to `false`)
101
+ *
51
102
  * ### Result
52
103
  *
53
- * - `true`: `A` and `B` share at least one common type
54
- * - `false`: `A` and `B` are completely disjoint
104
+ * - `Yes`: `A` and `B` share at least one common type
105
+ * - `No`: `A` and `B` are completely disjoint
106
+ *
107
+ * @example
108
+ * ```ts
109
+ * type T1 = Overlap<1 | 2, 2 | 3> // true
110
+ * type T2 = Overlap<string, 'hello'> // true
111
+ * type F1 = Overlap<string, number> // false
112
+ * type F2 = Overlap<1, 'one'> // false
113
+ * ```
55
114
  */
56
115
  export type Overlap<A, B, Yes = true, No = false> = [A & B] extends [never] ? No : Yes;
57
116
  /**
@@ -59,10 +118,23 @@ export type Overlap<A, B, Yes = true, No = false> = [A & B] extends [never] ? No
59
118
  *
60
119
  * This is the logical negation of `Overlap<A, B>`.
61
120
  *
121
+ * @template A - The first type to check for disjointness
122
+ * @template B - The second type to check for disjointness
123
+ * @template Yes - The result if types are disjoint (defaults to `true`)
124
+ * @template No - The result if types are not disjoint (defaults to `false`)
125
+ *
62
126
  * ### Result
63
127
  *
64
- * - `true`: `A` and `B` have no overlap
65
- * - `false`: `A` and `B` share at least one common type
128
+ * - `Yes`: `A` and `B` have no overlap
129
+ * - `No`: `A` and `B` share at least one common type
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * type T1 = Disjoint<string, number> // true
134
+ * type T2 = Disjoint<1, 'one'> // true
135
+ * type F1 = Disjoint<1 | 2, 2 | 3> // false
136
+ * type F2 = Disjoint<string, 'hello'> // false
137
+ * ```
66
138
  */
67
139
  export type Disjoint<A, B, Yes = true, No = false> = [A & B] extends [never] ? Yes : No;
68
140
  /**
@@ -74,6 +146,24 @@ export type Disjoint<A, B, Yes = true, No = false> = [A & B] extends [never] ? Y
74
146
  *
75
147
  * In other words, the two types describe the same set of values,
76
148
  * even if they are written differently.
149
+ *
150
+ * @template A - The first type to check
151
+ * @template B - The second type to check
152
+ * @template Yes - The result if types are mutually assignable (defaults to `true`)
153
+ * @template No - The result if types are not mutually assignable (defaults to `false`)
154
+ *
155
+ * ### Result
156
+ *
157
+ * - `Yes`: `A` and `B` are mutually assignable
158
+ * - `No`: Otherwise
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * type T1 = MutuallyAssignable<number, number> // true
163
+ * type T2 = MutuallyAssignable<1 | 2, 2 | 1> // true
164
+ * type F1 = MutuallyAssignable<string, number> // false
165
+ * type F2 = MutuallyAssignable<1, number> // false
166
+ * ```
77
167
  */
78
168
  export type MutuallyAssignable<A, B, Yes = true, No = false> = [A] extends [B] ? [B] extends [A] ? Yes : No : No;
79
169
  //# sourceMappingURL=compare.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../../../src/main/type/compare.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,KAAK,CACf,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,CAAA;AAEpF;;;;;;;;;GASG;AACH,MAAM,MAAM,QAAQ,CAClB,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAA;AAEpF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,OAAO,CACjB,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,CAAA;AAE9B;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,CACtB,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,KAAK,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,CAAA;AAE/D;;;;;;;GAOG;AACH,MAAM,MAAM,OAAO,CACjB,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,CAAA;AAEtC;;;;;;;;;GASG;AACH,MAAM,MAAM,QAAQ,CAClB,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,EAAE,CAAA;AAEtC;;;;;;;;;GASG;AACH,MAAM,MAAM,kBAAkB,CAC5B,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,CAAA"}
1
+ {"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../../../src/main/type/compare.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,MAAM,KAAK,CACf,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,CAAA;AAEpF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,QAAQ,CAClB,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAA;AAEpF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,OAAO,CACjB,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,CAAA;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,YAAY,CACtB,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,KAAK,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,CAAA;AAE/D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,OAAO,CACjB,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,CAAA;AAEtC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,QAAQ,CAClB,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,EAAE,CAAA;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,MAAM,kBAAkB,CAC5B,CAAC,EACD,CAAC,EACD,GAAG,GAAG,IAAI,EACV,EAAE,GAAG,KAAK,IACR,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"compare.js","sourceRoot":"","sources":["../../../src/main/type/compare.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Checks whether two types are exactly the same.\n *\n * This performs a structural equality comparison between `A` and `B`,\n * rather than a one-way assignability check.\n *\n * ### Result\n *\n * - `true`: `A` and `B` are identical types\n * - `false`: Otherwise\n */\nexport type Exact<\n A,\n B,\n Yes = true,\n No = false,\n> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? Yes : No\n\n/**\n * Checks whether two types are not exactly the same.\n *\n * This is the logical negation of `Exact<A, B>`.\n *\n * ### Result\n *\n * - `true`: `A` and `B` are not identical\n * - `false`: `A` and `B` are exactly the same type\n */\nexport type NotExact<\n A,\n B,\n Yes = true,\n No = false,\n> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? No : Yes\n\n/**\n * Checks whether type `A` extends type `B`.\n *\n * This is a non-distributive version of `extends`, ensuring\n * the result is always a concrete boolean literal.\n *\n * ### Result\n *\n * - `true`: `A` is assignable to `B`\n * - `false`: Otherwise\n *\n * **Note:** the result will never be `boolean`.\n */\nexport type Extends<\n A,\n B,\n Yes = true,\n No = false,\n> = [A] extends [B] ? Yes : No\n\n/**\n * Checks whether type `A` is a *proper* subtype of type `B`.\n *\n * A proper extension means:\n * - `A` extends `B`\n * - `A` is not exactly the same type as `B`\n *\n * **Note:** the result will never be `boolean`.\n */\nexport type ProperExtend<\n A,\n B,\n Yes = true,\n No = false,\n> = [A] extends [B] ? Exact<A, B> extends false ? Yes : No : No\n\n/**\n * Checks whether two types have any overlapping members.\n *\n * ### Result\n *\n * - `true`: `A` and `B` share at least one common type\n * - `false`: `A` and `B` are completely disjoint\n */\nexport type Overlap<\n A,\n B,\n Yes = true,\n No = false,\n> = [A & B] extends [never] ? No : Yes\n\n/**\n * Checks whether two types are disjoint.\n *\n * This is the logical negation of `Overlap<A, B>`.\n *\n * ### Result\n *\n * - `true`: `A` and `B` have no overlap\n * - `false`: `A` and `B` share at least one common type\n */\nexport type Disjoint<\n A,\n B,\n Yes = true,\n No = false,\n> = [A & B] extends [never] ? Yes : No\n\n/**\n * Checks whether two types are mutually assignable.\n *\n * This is equivalent to checking that:\n * - `A` extends `B`\n * - `B` extends `A`\n *\n * In other words, the two types describe the same set of values,\n * even if they are written differently.\n */\nexport type MutuallyAssignable<\n A,\n B,\n Yes = true,\n No = false,\n> = [A] extends [B] ? [B] extends [A] ? Yes : No : No\n"]}
1
+ {"version":3,"file":"compare.js","sourceRoot":"","sources":["../../../src/main/type/compare.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Checks whether two types are exactly the same.\n *\n * **⚠️Important:** parameter `A` and `B` are not distributive. When they are union type, it does not check each member separately.\n *\n * @template A - The first type to compare\n * @template B - The second type to compare\n * @template Yes - The result if types are exactly the same (defaults to `true`)\n * @template No - The result if types are not exactly the same (defaults to `false`)\n *\n * ### Result\n *\n * - `Yes`: `A` and `B` are exactly the same\n * - `No`: Otherwise\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * expect<Exact<string, string>>().toBeTrue\n * expect<Exact<never, never>>().toBeTrue\n * expect<Exact<any, any>>().toBeTrue\n *\n * expect<Exact<{ a: 3 }, { a?: 3 }>>().toBeFalse\n * expect<Exact<1 | 2, 1>>().toBeFalse\n * expect<Exact<1, number>>().toBeFalse\n * expect<Exact<() => void, () => undefined>>().toBeFalse\n * ```\n */\nexport type Exact<\n A,\n B,\n Yes = true,\n No = false,\n> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? Yes : No\n\n/**\n * Checks whether two types are not exactly the same.\n *\n * This is the logical negation of `Exact<A, B>`.\n *\n * @template A - The first type to compare\n * @template B - The second type to compare\n * @template Yes - The result if types are not exactly the same (defaults to `true`)\n * @template No - The result if types are exactly the same (defaults to `false`)\n *\n * @example\n * ```ts\n * type T1 = NotExact<number, string> // true\n * type T2 = NotExact<1, number> // true\n * type F1 = NotExact<number, number> // false\n * type F2 = NotExact<1, 1> // false\n * ```\n */\nexport type NotExact<\n A,\n B,\n Yes = true,\n No = false,\n> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? No : Yes\n\n/**\n * Checks whether type `A` extends type `B`.\n *\n * **⚠️Important:** parameter `A` and `B` are not distributive. When they are union type, it treats them as a single entity.\n *\n * @template A - The type to check if it extends another type\n * @template B - The type to check if `A` extends\n * @template Yes - The result if `A` extends `B` (defaults to `true`)\n * @template No - The result if `A` does not extend `B` (defaults to `false`)\n *\n * ### Result\n *\n * - `Yes`: `A` is assignable to `B`\n * - `No`: Otherwise\n */\nexport type Extends<\n A,\n B,\n Yes = true,\n No = false,\n> = [A] extends [B] ? Yes : No\n\n/**\n * Checks whether type `A` is a *proper* subtype of type `B`.\n *\n * A proper extension means:\n * - `A` extends `B`\n * - `A` is not exactly the same type as `B`\n *\n * @template A - The type to check if it is a proper subtype\n * @template B - The type to check against\n * @template Yes - The result if `A` is a proper subtype of `B` (defaults to `true`)\n * @template No - The result if `A` is not a proper subtype of `B` (defaults to `false`)\n *\n * ### Result\n *\n * - `Yes`: `A` is a proper subtype of `B`\n * - `No`: Otherwise\n *\n * **Note:** the result will never be `boolean`.\n *\n * @example\n * ```ts\n * type T1 = ProperExtend<true, boolean> // true\n * type T2 = ProperExtend<1, number> // true\n * type F1 = ProperExtend<boolean, boolean> // false\n * type F2 = ProperExtend<number, string> // false\n * ```\n */\nexport type ProperExtend<\n A,\n B,\n Yes = true,\n No = false,\n> = [A] extends [B] ? Exact<A, B> extends false ? Yes : No : No\n\n/**\n * Checks whether two types have any overlapping members.\n *\n * @template A - The first type to check for overlap\n * @template B - The second type to check for overlap\n * @template Yes - The result if types overlap (defaults to `true`)\n * @template No - The result if types do not overlap (defaults to `false`)\n *\n * ### Result\n *\n * - `Yes`: `A` and `B` share at least one common type\n * - `No`: `A` and `B` are completely disjoint\n *\n * @example\n * ```ts\n * type T1 = Overlap<1 | 2, 2 | 3> // true\n * type T2 = Overlap<string, 'hello'> // true\n * type F1 = Overlap<string, number> // false\n * type F2 = Overlap<1, 'one'> // false\n * ```\n */\nexport type Overlap<\n A,\n B,\n Yes = true,\n No = false,\n> = [A & B] extends [never] ? No : Yes\n\n/**\n * Checks whether two types are disjoint.\n *\n * This is the logical negation of `Overlap<A, B>`.\n *\n * @template A - The first type to check for disjointness\n * @template B - The second type to check for disjointness\n * @template Yes - The result if types are disjoint (defaults to `true`)\n * @template No - The result if types are not disjoint (defaults to `false`)\n *\n * ### Result\n *\n * - `Yes`: `A` and `B` have no overlap\n * - `No`: `A` and `B` share at least one common type\n *\n * @example\n * ```ts\n * type T1 = Disjoint<string, number> // true\n * type T2 = Disjoint<1, 'one'> // true\n * type F1 = Disjoint<1 | 2, 2 | 3> // false\n * type F2 = Disjoint<string, 'hello'> // false\n * ```\n */\nexport type Disjoint<\n A,\n B,\n Yes = true,\n No = false,\n> = [A & B] extends [never] ? Yes : No\n\n/**\n * Checks whether two types are mutually assignable.\n *\n * This is equivalent to checking that:\n * - `A` extends `B`\n * - `B` extends `A`\n *\n * In other words, the two types describe the same set of values,\n * even if they are written differently.\n *\n * @template A - The first type to check\n * @template B - The second type to check\n * @template Yes - The result if types are mutually assignable (defaults to `true`)\n * @template No - The result if types are not mutually assignable (defaults to `false`)\n *\n * ### Result\n *\n * - `Yes`: `A` and `B` are mutually assignable\n * - `No`: Otherwise\n *\n * @example\n * ```ts\n * type T1 = MutuallyAssignable<number, number> // true\n * type T2 = MutuallyAssignable<1 | 2, 2 | 1> // true\n * type F1 = MutuallyAssignable<string, number> // false\n * type F2 = MutuallyAssignable<1, number> // false\n * ```\n */\nexport type MutuallyAssignable<\n A,\n B,\n Yes = true,\n No = false,\n> = [A] extends [B] ? [B] extends [A] ? Yes : No : No\n"]}