lay-sing 0.1.2 → 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 (117) hide show
  1. package/README.md +78 -66
  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 -20
  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 +70 -46
  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 -5
  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 +6 -1
  19. package/esm/main/index.d.ts.map +1 -1
  20. package/esm/main/index.js +8 -1
  21. package/esm/main/index.js.map +1 -1
  22. package/esm/main/key.d.ts +51 -13
  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 +74 -35
  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 +64 -0
  29. package/esm/main/tuple.d.ts.map +1 -0
  30. package/esm/main/tuple.js +2 -0
  31. package/esm/main/tuple.js.map +1 -0
  32. package/esm/main/type/compare.d.ts +118 -28
  33. package/esm/main/type/compare.d.ts.map +1 -1
  34. package/esm/main/type/compare.js.map +1 -1
  35. package/esm/main/type/index.d.ts.map +1 -1
  36. package/esm/main/type/index.js +2 -0
  37. package/esm/main/type/index.js.map +1 -1
  38. package/esm/main/type/set.d.ts +17 -12
  39. package/esm/main/type/set.d.ts.map +1 -1
  40. package/esm/main/type/set.js.map +1 -1
  41. package/esm/test-utils/compare.d.ts +81 -0
  42. package/esm/test-utils/compare.d.ts.map +1 -0
  43. package/esm/test-utils/compare.js +2 -0
  44. package/esm/test-utils/compare.js.map +1 -0
  45. package/esm/test-utils/expect.d.ts +278 -0
  46. package/esm/test-utils/expect.d.ts.map +1 -0
  47. package/esm/test-utils/expect.js +2 -0
  48. package/esm/test-utils/expect.js.map +1 -0
  49. package/esm/test-utils/index.d.ts +77 -0
  50. package/esm/test-utils/index.d.ts.map +1 -0
  51. package/esm/{test-utils.js → test-utils/index.js} +9 -5
  52. package/esm/test-utils/index.js.map +1 -0
  53. package/package.json +3 -3
  54. package/script/main/async.d.ts +9 -1
  55. package/script/main/async.d.ts.map +1 -1
  56. package/script/main/async.js.map +1 -1
  57. package/script/main/boolean.d.ts +43 -20
  58. package/script/main/boolean.d.ts.map +1 -1
  59. package/script/main/boolean.js.map +1 -1
  60. package/script/main/control.d.ts +70 -46
  61. package/script/main/control.d.ts.map +1 -1
  62. package/script/main/control.js.map +1 -1
  63. package/script/main/doc.d.ts +33 -7
  64. package/script/main/doc.d.ts.map +1 -1
  65. package/script/main/doc.js.map +1 -1
  66. package/script/main/function.d.ts +11 -5
  67. package/script/main/function.d.ts.map +1 -1
  68. package/script/main/function.js +0 -1
  69. package/script/main/function.js.map +1 -1
  70. package/script/main/index.d.ts +6 -1
  71. package/script/main/index.d.ts.map +1 -1
  72. package/script/main/index.js +8 -1
  73. package/script/main/index.js.map +1 -1
  74. package/script/main/key.d.ts +51 -13
  75. package/script/main/key.d.ts.map +1 -1
  76. package/script/main/key.js.map +1 -1
  77. package/script/main/object.d.ts +74 -35
  78. package/script/main/object.d.ts.map +1 -1
  79. package/script/main/object.js.map +1 -1
  80. package/script/main/tuple.d.ts +64 -0
  81. package/script/main/tuple.d.ts.map +1 -0
  82. package/script/main/{array.js → tuple.js} +1 -1
  83. package/script/main/tuple.js.map +1 -0
  84. package/script/main/type/compare.d.ts +118 -28
  85. package/script/main/type/compare.d.ts.map +1 -1
  86. package/script/main/type/compare.js.map +1 -1
  87. package/script/main/type/index.d.ts.map +1 -1
  88. package/script/main/type/index.js +2 -0
  89. package/script/main/type/index.js.map +1 -1
  90. package/script/main/type/set.d.ts +17 -12
  91. package/script/main/type/set.d.ts.map +1 -1
  92. package/script/main/type/set.js.map +1 -1
  93. package/script/test-utils/compare.d.ts +81 -0
  94. package/script/test-utils/compare.d.ts.map +1 -0
  95. package/script/test-utils/compare.js +3 -0
  96. package/script/test-utils/compare.js.map +1 -0
  97. package/script/test-utils/expect.d.ts +278 -0
  98. package/script/test-utils/expect.d.ts.map +1 -0
  99. package/script/test-utils/expect.js +3 -0
  100. package/script/test-utils/expect.js.map +1 -0
  101. package/script/test-utils/index.d.ts +77 -0
  102. package/script/test-utils/index.d.ts.map +1 -0
  103. package/script/{test-utils.js → test-utils/index.js} +10 -6
  104. package/script/test-utils/index.js.map +1 -0
  105. package/esm/main/array.d.ts +0 -48
  106. package/esm/main/array.d.ts.map +0 -1
  107. package/esm/main/array.js +0 -2
  108. package/esm/main/array.js.map +0 -1
  109. package/esm/test-utils.d.ts +0 -348
  110. package/esm/test-utils.d.ts.map +0 -1
  111. package/esm/test-utils.js.map +0 -1
  112. package/script/main/array.d.ts +0 -48
  113. package/script/main/array.d.ts.map +0 -1
  114. package/script/main/array.js.map +0 -1
  115. package/script/test-utils.d.ts +0 -348
  116. package/script/test-utils.d.ts.map +0 -1
  117. package/script/test-utils.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"doc.js","sourceRoot":"","sources":["../../src/main/doc.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Append documentation or auxiliary metadata to type `A`\n * without changing its shape.\n *\n * This type intersects `Doc` onto `A`, but only keeps the keys\n * originally defined in `A`. As a result:\n *\n * - `Doc` cannot introduce new properties\n * - Existing properties in `A` are preserved\n * - `Doc` may further constrain or annotate existing properties\n *\n * This is typically used to attach JSDoc comments, branding,\n * or editor-only metadata to an existing type while keeping\n * its public structure intact.\n */\nexport type AppendDoc<T, Doc> = Pick<T & Doc, keyof T>\n\n/**\n * Prepend documentation or auxiliary metadata to type `A`\n * without changing its shape.\n *\n * This is similar to {@link AppendDoc}, but the intersection order\n * is reversed (`Doc & A`), which can affect how property types,\n * documentation, and hover information are presented by tooling.\n *\n * In practice, this allows `Doc` to act as a non-invasive,\n * descriptive layer while ensuring `A` remains the authoritative\n * source of truth for property types.\n */\nexport type PrependDoc<T, Doc> = Pick<Doc & T, keyof T>\n"]}
1
+ {"version":3,"file":"doc.js","sourceRoot":"","sources":["../../src/main/doc.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Append documentation or auxiliary metadata to type `T`\n * without changing its shape.\n *\n * This type intersects `Doc` onto `T`, but only keeps the keys\n * originally defined in `T`. As a result:\n *\n * - `Doc` cannot introduce new properties\n * - Existing properties in `T` are preserved\n * - `Doc` may further constrain or annotate existing properties\n *\n * This is typically used to attach JSDoc comments, branding,\n * or editor-only metadata to an existing type while keeping\n * its public structure intact.\n *\n * @template T - The target type to append documentation to\n * @template Doc - The documentation or metadata type to append\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * type User = { name: string; age: number }\n * type UserWithDoc = AppendDoc<User, { name: string }>\n *\n * expect<UserWithDoc>().toBe<User>().success\n * ```\n */\nexport type AppendDoc<T, Doc> = Pick<T & Doc, keyof T>\n\n/**\n * Prepend documentation or auxiliary metadata to type `T`\n * without changing its shape.\n *\n * This is similar to {@link AppendDoc}, but the intersection order\n * is reversed (`Doc & T`), which can affect how property types,\n * documentation, and hover information are presented by tooling.\n *\n * In practice, this allows `Doc` to act as a non-invasive,\n * descriptive layer while ensuring `T` remains the authoritative\n * source of truth for property types.\n *\n * @template T - The target type to prepend documentation to\n * @template Doc - The documentation or metadata type to prepend\n *\n * @example\n * ```ts\n * import { expect } from '@leawind/lay-sing/test-utils'\n *\n * type User = { name: string; age: number }\n * type UserWithDoc = PrependDoc<User, { age: number }>\n *\n * expect<UserWithDoc>().toBe<User>().success\n * ```\n */\nexport type PrependDoc<T, Doc> = Pick<Doc & T, keyof T>\n"]}
@@ -1,20 +1,26 @@
1
1
  /**
2
2
  * Represents a function with any parameters and a specific return type
3
3
  *
4
- * ### Examples
4
+ * @template Return - The return type of the function
5
+ * @template Params - The parameters of the function as a tuple type
5
6
  *
7
+ * @example
6
8
  * ```ts
7
- * type _ = AnyFunction<string, [number]> // (arg: number) => string
9
+ * type NumberToStringFn = AnyFunction<string, [number]>
10
+ * // Equivalent to: (arg: number) => string
8
11
  * ```
9
12
  */
10
13
  export type AnyFunction<Return = any, Params extends any[] = any[]> = (...args: Params) => Return;
11
14
  /**
12
- * Represents a constructor with any parameters and a specific return type
15
+ * Represents a constructor function with any parameters and a specific return type
13
16
  *
14
- * ### Examples
17
+ * @template Return - The type returned by the constructor function
18
+ * @template Params - The parameters of the constructor function as a tuple type
15
19
  *
20
+ * @example
16
21
  * ```ts
17
- * type _ = Constructor<string, [number]> // new (arg: number) => string
22
+ * type StringConstructor = Constructor<string, [number]>
23
+ * // Equivalent to: new (arg: number) => string
18
24
  * ```
19
25
  */
20
26
  export type Constructor<Return = any, Params extends any[] = any[]> = new (...args: Params) => Return;
@@ -1 +1 @@
1
- {"version":3,"file":"function.d.ts","sourceRoot":"","sources":["../../src/main/function.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,CACrB,MAAM,GAAG,GAAG,EACZ,MAAM,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,IAC1B,CAAC,GAAG,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;AAE/B;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,CACrB,MAAM,GAAG,GAAG,EACZ,MAAM,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,IAC1B,KAAK,GAAG,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA"}
1
+ {"version":3,"file":"function.d.ts","sourceRoot":"","sources":["../../src/main/function.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,CACrB,MAAM,GAAG,GAAG,EACZ,MAAM,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,IAC1B,CAAC,GAAG,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;AAE/B;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,CACrB,MAAM,GAAG,GAAG,EACZ,MAAM,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,IAC1B,KAAK,GAAG,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA"}
@@ -1,3 +1,2 @@
1
- // deno-lint-ignore-file no-explicit-any
2
1
  export {};
3
2
  //# sourceMappingURL=function.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"function.js","sourceRoot":"","sources":["../../src/main/function.ts"],"names":[],"mappings":"AAAA,wCAAwC","sourcesContent":["// deno-lint-ignore-file no-explicit-any\n\n/**\n * Represents a function with any parameters and a specific return type\n *\n * ### Examples\n *\n * ```ts\n * type _ = AnyFunction<string, [number]> // (arg: number) => string\n * ```\n */\nexport type AnyFunction<\n Return = any,\n Params extends any[] = any[],\n> = (...args: Params) => Return\n\n/**\n * Represents a constructor with any parameters and a specific return type\n *\n * ### Examples\n *\n * ```ts\n * type _ = Constructor<string, [number]> // new (arg: number) => string\n * ```\n */\nexport type Constructor<\n Return = any,\n Params extends any[] = any[],\n> = new (...args: Params) => Return\n"]}
1
+ {"version":3,"file":"function.js","sourceRoot":"","sources":["../../src/main/function.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Represents a function with any parameters and a specific return type\n *\n * @template Return - The return type of the function\n * @template Params - The parameters of the function as a tuple type\n *\n * @example\n * ```ts\n * type NumberToStringFn = AnyFunction<string, [number]>\n * // Equivalent to: (arg: number) => string\n * ```\n */\nexport type AnyFunction<\n Return = any,\n Params extends any[] = any[],\n> = (...args: Params) => Return\n\n/**\n * Represents a constructor function with any parameters and a specific return type\n *\n * @template Return - The type returned by the constructor function\n * @template Params - The parameters of the constructor function as a tuple type\n *\n * @example\n * ```ts\n * type StringConstructor = Constructor<string, [number]>\n * // Equivalent to: new (arg: number) => string\n * ```\n */\nexport type Constructor<\n Return = any,\n Params extends any[] = any[],\n> = new (...args: Params) => Return\n"]}
@@ -1,4 +1,8 @@
1
- export * from './array.js';
1
+ /**
2
+ * [Full API documentation is available on JSR](https://jsr.io/@leawind/lay-sing/doc)
3
+ *
4
+ * @module
5
+ */
2
6
  export * from './async.js';
3
7
  export * from './boolean.js';
4
8
  export * from './control.js';
@@ -7,6 +11,7 @@ export * from './function.js';
7
11
  export * from './json.js';
8
12
  export * from './key.js';
9
13
  export * from './object.js';
14
+ export * from './tuple.js';
10
15
  export * from './type/index.js';
11
16
  export * from './typed-array.js';
12
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/main/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/main/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,kBAAkB,CAAA"}
package/esm/main/index.js CHANGED
@@ -1,4 +1,9 @@
1
- export * from './array.js';
1
+ /**
2
+ * [Full API documentation is available on JSR](https://jsr.io/@leawind/lay-sing/doc)
3
+ *
4
+ * @module
5
+ */
6
+ // Index start >>>>>>>>>>>>>>>>
2
7
  export * from './async.js';
3
8
  export * from './boolean.js';
4
9
  export * from './control.js';
@@ -7,6 +12,8 @@ export * from './function.js';
7
12
  export * from './json.js';
8
13
  export * from './key.js';
9
14
  export * from './object.js';
15
+ export * from './tuple.js';
10
16
  export * from './type/index.js';
11
17
  export * from './typed-array.js';
18
+ // <<<<<<<<<<<<<<<< Index end
12
19
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/main/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,kBAAkB,CAAA","sourcesContent":["export * from './array.js'\nexport * from './async.js'\nexport * from './boolean.js'\nexport * from './control.js'\nexport * from './doc.js'\nexport * from './function.js'\nexport * from './json.js'\nexport * from './key.js'\nexport * from './object.js'\nexport * from './type/index.js'\nexport * from './typed-array.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/main/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,+BAA+B;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,kBAAkB,CAAA;AAChC,+BAA+B","sourcesContent":["/**\n * [Full API documentation is available on JSR](https://jsr.io/@leawind/lay-sing/doc)\n *\n * @module\n */\n\n// Index start >>>>>>>>>>>>>>>>\nexport * from './async.js'\nexport * from './boolean.js'\nexport * from './control.js'\nexport * from './doc.js'\nexport * from './function.js'\nexport * from './json.js'\nexport * from './key.js'\nexport * from './object.js'\nexport * from './tuple.js'\nexport * from './type/index.js'\nexport * from './typed-array.js'\n// <<<<<<<<<<<<<<<< Index end\n"]}
package/esm/main/key.d.ts CHANGED
@@ -1,26 +1,64 @@
1
- import type { Same } from './type/index.js';
1
+ import type { Exact } from './type/index.js';
2
2
  /**
3
- * Extracts the keys of type T that have values of type U
3
+ * Extracts the keys of an object whose **base value type** matches the specified `ValueType` (ignoring undefined from optional properties).
4
4
  *
5
- * ### Examples
5
+ * This utility matches the underlying/base type of each property (stripping `undefined` added by optional modifiers `?`).
6
+ * For optional properties (e.g., `a?: string`), the type is treated as `string` – no need to include `undefined` in `ValueType` to match.
6
7
  *
8
+ * @template Obj - The target object type to extract keys from.
9
+ * @template ValueType - The base type to match against property values (ignoring undefined from optional properties).
10
+ *
11
+ * @example
7
12
  * ```ts
8
- * type A = { a: 1; b: 2; c: 1 }
9
- * type Keys = KeysOfType<A, 1> // 'a' | 'c'
13
+ * import { expect } from '@leawind/lay-sing/test-utils'
14
+ *
15
+ * // Basic usage: match base type (non-optional property)
16
+ * type A = { a: 1; b: 2; c: 1 };
17
+ * expect<KeysOfBaseType<A, 1>>().toBe<'a' | 'c'>().success
18
+ *
19
+ * // Key difference: optional property matching (ignores undefined)
20
+ * type B = { a?: string; b: string };
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
23
+ *
24
+ * type C = { a: never; b: any; c: unknown };
25
+ * expect<KeysOfBaseType<C, never>>().toBe<'a'>().success
26
+ * expect<KeysOfBaseType<C, any>>().toBe<'b'>().success
27
+ * expect<KeysOfBaseType<C, unknown>>().toBe<'c'>().success
10
28
  * ```
11
29
  */
12
- export type KeysOfType<T, U> = Exclude<{
13
- [K in keyof T]: Same<T[K], U> extends true ? K : never;
14
- }[keyof T], undefined>;
30
+ export type KeysOfBaseType<Obj, ValueType> = Exclude<{
31
+ [K in keyof Obj]: Exact<Required<Obj>[K], ValueType> extends true ? K : never;
32
+ }[keyof Obj], undefined>;
15
33
  /**
16
- * Extracts the keys of type T that do not have values of type U
34
+ * Extracts the keys of an object whose **complete value type** exactly matches the specified `ValueType` (including undefined for optional properties).
17
35
  *
18
- * ### Examples
36
+ * This utility strictly matches the full type of each property (including `undefined` added by optional modifiers `?`).
37
+ * For optional properties (e.g., `a?: string`), the type is treated as `string | undefined` – to match, `ValueType` must include `undefined`.
19
38
  *
39
+ * @template Obj - The target object type to extract keys from.
40
+ * @template ValueType - The exact type to match against property values (including undefined for optional properties).
41
+ *
42
+ * @example
20
43
  * ```ts
21
- * type A = { a: 1; b: 2; c: 1 }
22
- * type Keys = KeysOfOtherType<A, 1> // 'b'
44
+ * import { expect } from '@leawind/lay-sing/test-utils'
45
+ *
46
+ * // Basic usage: match exact type (non-optional property)
47
+ * type A = { a: 1; b: 2; c: 1 };
48
+ * expect<KeysOfExactType<A, 1>>().toBe<'a' | 'c'>().success
49
+ *
50
+ * // Key difference: optional property matching (requires undefined in `ValueType`)
51
+ * type B = { a?: string };
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
54
+ *
55
+ * type C = { a: never; b: any; c: unknown };
56
+ * expect<KeysOfExactType<C, never>>().toBe<'a'>().success
57
+ * expect<KeysOfExactType<C, any>>().toBe<'b'>().success
58
+ * expect<KeysOfExactType<C, unknown>>().toBe<'c'>().success
23
59
  * ```
24
60
  */
25
- export type KeysOfOtherType<T, U> = Exclude<keyof T, KeysOfType<T, U>>;
61
+ export type KeysOfExactType<Obj, ValueType> = Exclude<{
62
+ [K in keyof Obj]: Exact<Obj[K], ValueType> extends true ? K : never;
63
+ }[keyof Obj], undefined>;
26
64
  //# sourceMappingURL=key.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"key.d.ts","sourceRoot":"","sources":["../../src/main/key.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAE3C;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK;CAAE,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;AAEtH;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,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 { Same } from './type/index.js'\n\n/**\n * Extracts the keys of type T that have values of type U\n *\n * ### Examples\n *\n * ```ts\n * type A = { a: 1; b: 2; c: 1 }\n * type Keys = KeysOfType<A, 1> // 'a' | 'c'\n * ```\n */\nexport type KeysOfType<T, U> = Exclude<{ [K in keyof T]: Same<T[K], U> extends true ? K : never }[keyof T], undefined>\n\n/**\n * Extracts the keys of type T that do not have values of type U\n *\n * ### Examples\n *\n * ```ts\n * type A = { a: 1; b: 2; c: 1 }\n * type Keys = KeysOfOtherType<A, 1> // 'b'\n * ```\n */\nexport type KeysOfOtherType<T, U> = Exclude<keyof T, KeysOfType<T, U>>\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,22 +1,55 @@
1
- import type { KeysOfOtherType, KeysOfType } from './key.js';
1
+ import type { KeysOfExactType } from './key.js';
2
2
  /**
3
- * Access a property `K` of object `T`, with a fallback `E` if the property doesn't exist
3
+ * Get property type from object, with fallback for missing keys.
4
4
  *
5
- * ### Examples
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`)
6
8
  *
9
+ * @returns `Obj[K]` if key exists, otherwise `E`.
10
+ *
11
+ * @example
12
+ * ```ts
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
20
+ * ```
21
+ */
22
+ export type Access<Obj, K extends PropertyKey, E = never> = K extends keyof Obj ? Obj[K] : E;
23
+ /**
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`)
29
+ *
30
+ * @example
7
31
  * ```ts
8
- * type Result = Access<{ a: string }, 'a'> // string
9
- * type Missing = Access<{ a: string }, 'x', 'default'> // 'default'
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
10
37
  * ```
11
38
  */
12
- export type Access<T, K extends PropertyKey, E = never> = K extends keyof T ? T[K] : E;
39
+ export type InverseAccess<T, V, E = never> = {
40
+ [K in keyof T]: T[K] extends V ? K : E;
41
+ }[keyof T];
13
42
  /**
14
43
  * Recursively makes all properties of `T` optional
15
44
  *
16
- * ### Examples
45
+ * @template T - The object type to make deep partial
17
46
  *
47
+ * @example
18
48
  * ```ts
19
- * 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
20
53
  * ```
21
54
  */
22
55
  export type DeepPartial<T> = {
@@ -25,57 +58,63 @@ export type DeepPartial<T> = {
25
58
  /**
26
59
  * Recursively makes all properties of `T` required
27
60
  *
28
- * ### Examples
61
+ * @template T - The object type to make deep required
29
62
  *
63
+ * @example
30
64
  * ```ts
31
- * type Result = DeepRequire<{ a?: string; nested?: { b?: number } }>
32
- * // { a: string; nested: { b: number } }
65
+ * import { expect } from '@leawind/lay-sing/test-utils'
66
+ *
67
+ * expect<DeepRequire<{ _?: { _?: 1 } }>>().toBe<{ _: { _: 1 } }>().success
33
68
  * ```
34
69
  */
35
70
  export type DeepRequire<T> = {
36
- [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];
37
72
  };
38
73
  /**
39
- * Returns `T` if `T` extends `A`, otherwise returns never
40
- *
41
- * ### Examples
74
+ * **⚠️Important:** parameter `T` and `U` are not distributive. When they are union type, it treats them as a single entity.
42
75
  *
43
- * ```ts
44
- * type _1 = AssertExtends<string, string> // string
45
- * type _2 = AssertExtends<string, number> // never
46
- * ```
47
- */
48
- export type AssertExtends<T, A> = T extends A ? T : never;
49
- /**
50
- * Safely picks keys `K` from type T, excluding non-existent keys
76
+ * @template T - The type to test (not distributed over unions)
77
+ * @template U - The constraint type to test against
51
78
  *
52
- * ### Examples
79
+ * @example
53
80
  *
54
81
  * ```ts
55
- * type Result = SafePick<{ a: string; b: number }, 'a' | 'c'> // { a: string }
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
56
87
  * ```
57
88
  */
58
- export type SafePick<T, K> = Pick<T, K & keyof T>;
89
+ export type AssertExtends<T, U> = [T] extends [U] ? T : never;
59
90
  /**
60
- * Picks properties from `T` that have values of type U
91
+ * Safely picks keys `Key` from type `Obj`, excluding non-existent keys
61
92
  *
62
- * ### Examples
93
+ * @template Obj - The object type to pick keys from
94
+ * @template Key - The keys to pick from the object
63
95
  *
96
+ * @example
64
97
  * ```ts
65
- * type A = { a: string; b: number; c: string }
66
- * type Strings = PropsOfType<A, string> // { a: string; c: 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
67
102
  * ```
68
103
  */
69
- export type PropsOfType<T, U> = Pick<T, KeysOfType<T, U>>;
104
+ export type SafePick<Obj, Key> = Pick<Obj, Key & keyof Obj>;
70
105
  /**
71
- * Picks properties from `T` that do not have values of type U
106
+ * Picks properties from `T` that have values of type `U`
72
107
  *
73
- * ### Examples
108
+ * @template T - The object type to pick properties from
109
+ * @template U - The value type to match against
74
110
  *
111
+ * @example
75
112
  * ```ts
113
+ * import { expect } from '@leawind/lay-sing/test-utils'
76
114
  * type A = { a: string; b: number; c: string }
77
- * type NonStrings = PropsOfOtherType<A, string> // { b: number }
115
+ * type Strings = PropsOfBaseType<A, string> // { a: string; c: string }
116
+ * expect<PropsOfBaseType<A, string>>().toBe<{ a: string; c: string }>()
78
117
  * ```
79
118
  */
80
- export type PropsOfOtherType<T, U> = Pick<T, KeysOfOtherType<T, U>>;
119
+ export type PropsOfBaseType<T, U> = Pick<T, KeysOfExactType<Required<T>, U>>;
81
120
  //# sourceMappingURL=object.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../../src/main/object.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAE3D;;;;;;;;;GASG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,EAAE,CAAC,SAAS,WAAW,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;AAEtF;;;;;;;;GAQG;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;;;;;;;;;GASG;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;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAEzD;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAA;AAEjD;;;;;;;;;GASG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;AAEzD;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,eAAe,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 { KeysOfOtherType, KeysOfType } from './key.js'\n\n/**\n * Access a property `K` of object `T`, with a fallback `E` if the property doesn't exist\n *\n * ### Examples\n *\n * ```ts\n * type Result = Access<{ a: string }, 'a'> // string\n * type Missing = Access<{ a: string }, 'x', 'default'> // 'default'\n * ```\n */\nexport type Access<T, K extends PropertyKey, E = never> = K extends keyof T ? T[K] : E\n\n/**\n * Recursively makes all properties of `T` optional\n *\n * ### Examples\n *\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 * ### Examples\n *\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 * Returns `T` if `T` extends `A`, otherwise returns never\n *\n * ### Examples\n *\n * ```ts\n * type _1 = AssertExtends<string, string> // string\n * type _2 = AssertExtends<string, number> // never\n * ```\n */\nexport type AssertExtends<T, A> = T extends A ? T : never\n\n/**\n * Safely picks keys `K` from type T, excluding non-existent keys\n *\n * ### Examples\n *\n * ```ts\n * type Result = SafePick<{ a: string; b: number }, 'a' | 'c'> // { a: string }\n * ```\n */\nexport type SafePick<T, K> = Pick<T, K & keyof T>\n\n/**\n * Picks properties from `T` that have values of type U\n *\n * ### Examples\n *\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 PropsOfType<T, U> = Pick<T, KeysOfType<T, U>>\n\n/**\n * Picks properties from `T` that do not have values of type U\n *\n * ### Examples\n *\n * ```ts\n * type A = { a: string; b: number; c: string }\n * type NonStrings = PropsOfOtherType<A, string> // { b: number }\n * ```\n */\nexport type PropsOfOtherType<T, U> = Pick<T, KeysOfOtherType<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"]}
@@ -0,0 +1,64 @@
1
+ import type { Exact } from './type/compare.js';
2
+ /**
3
+ * Concatenates two tuples into a single tuple type
4
+ *
5
+ * @template Left - The first tuple type to concatenate
6
+ * @template Right - The second tuple type to concatenate
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { expect } from '@leawind/lay-sing/test-utils'
11
+ *
12
+ * expect<ConcatTuple<[1, 2], [3, 4]>>().toBe<[1, 2, 3, 4]>().success
13
+ * ```
14
+ */
15
+ export type ConcatTuple<Left extends readonly unknown[], Right extends readonly unknown[]> = Left extends readonly unknown[] ? (Right extends readonly unknown[] ? [...Left, ...Right] : never) : never;
16
+ /**
17
+ * Checks whether a tuple includes a specific element type
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
+ *
24
+ * @example
25
+ * ```ts
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
31
+ * ```
32
+ */
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;
34
+ /**
35
+ * Appends an element to a tuple only if it doesn't already exist in the tuple
36
+ *
37
+ * @template Tuple - The tuple type to append to
38
+ * @template Element - The element type to append
39
+ *
40
+ * @example
41
+ * ```ts
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
46
+ * ```
47
+ */
48
+ export type AppendUnique<Tuple extends readonly unknown[], Element> = IfTupleIncludes<Tuple, Element> extends true ? Tuple : [...Tuple, Element];
49
+ /**
50
+ * Concatenates two tuples while ensuring uniqueness of elements
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
+ *
56
+ * @example
57
+ * ```ts
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
61
+ * ```
62
+ */
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;
64
+ //# sourceMappingURL=tuple.d.ts.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tuple.js.map
@@ -0,0 +1 @@
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"]}