@mxweb/classable 1.1.0 → 1.1.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.1.1] - 2026-01-18
9
+
10
+ ### Added
11
+
12
+ - **Type Utilities**
13
+ - `SyncClassableByResolver<T, Args, Runtime>` - Specialized resolver interface with synchronous `resolve` function, enables correct type inference for sync instantiation
14
+ - `AsyncClassableByResolver<T, Args, Runtime>` - Specialized resolver interface with asynchronous `resolve` function, enables correct type inference for async instantiation
15
+
16
+ ### Fixed
17
+
18
+ - **classable.create() type overloads**
19
+ - Added missing overload for `Classable<InstanceType, []>` to properly handle resolvers with empty args and no runtime
20
+ - Fixed return type inference: now correctly returns `InstanceType` for sync resolvers and `Promise<InstanceType>` for async resolvers
21
+ - Improved overload ordering for better TypeScript type narrowing
22
+
8
23
  ## [1.1.0] - 2026-01-17
9
24
 
10
25
  ### Added
package/dist/index.d.ts CHANGED
@@ -106,6 +106,78 @@ export interface ClassableByResolver<InstanceType, Args extends Readonlyable<any
106
106
  */
107
107
  resolve: (...args: Runtime extends never ? [] : [runtime: Runtime]) => Args | Promise<Args>;
108
108
  }
109
+ /**
110
+ * A resolver configuration with synchronous argument resolution.
111
+ *
112
+ * This interface is a specialized version of `ClassableByResolver` where the
113
+ * `resolve` function is guaranteed to return arguments synchronously (not a Promise).
114
+ * Use this type when you need TypeScript to correctly infer that `classable.create()`
115
+ * returns `InstanceType` directly instead of `Promise<InstanceType>`.
116
+ *
117
+ * @template InstanceType - The type of instance to be created.
118
+ * @template Args - Tuple type of constructor arguments.
119
+ * @template Runtime - Optional runtime context type passed to the resolver.
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * // Without runtime context
124
+ * const simpleResolver: SyncClassableByResolver<User, [string, number]> = {
125
+ * target: User,
126
+ * resolve: () => ["John", 30]
127
+ * };
128
+ * const user = classable.create(simpleResolver); // Type: User
129
+ *
130
+ * // With runtime context
131
+ * const contextResolver: SyncClassableByResolver<User, [string], AppContext> = {
132
+ * target: User,
133
+ * resolve: (ctx) => [ctx.userName]
134
+ * };
135
+ * const user2 = classable.create(contextResolver, appContext); // Type: User
136
+ * ```
137
+ */
138
+ export interface SyncClassableByResolver<InstanceType, Args extends Readonlyable<any[]> = [], Runtime = never> {
139
+ target: ClassType<InstanceType, [...Args]>;
140
+ resolve: (...args: Runtime extends never ? [] : [runtime: Runtime]) => Args;
141
+ }
142
+ /**
143
+ * A resolver configuration with asynchronous argument resolution.
144
+ *
145
+ * This interface is a specialized version of `ClassableByResolver` where the
146
+ * `resolve` function is guaranteed to return a Promise. Use this type when you
147
+ * need TypeScript to correctly infer that `classable.create()` returns
148
+ * `Promise<InstanceType>` instead of `InstanceType`.
149
+ *
150
+ * @template InstanceType - The type of instance to be created.
151
+ * @template Args - Tuple type of constructor arguments.
152
+ * @template Runtime - Optional runtime context type passed to the resolver.
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * // Without runtime context
157
+ * const asyncResolver: AsyncClassableByResolver<User, [string]> = {
158
+ * target: User,
159
+ * resolve: async () => {
160
+ * const name = await fetchUserName();
161
+ * return [name];
162
+ * }
163
+ * };
164
+ * const user = await classable.create(asyncResolver); // Type: Promise<User>
165
+ *
166
+ * // With runtime context
167
+ * const dbResolver: AsyncClassableByResolver<User, [string], DbContext> = {
168
+ * target: User,
169
+ * resolve: async (ctx) => {
170
+ * const name = await ctx.db.fetchName();
171
+ * return [name];
172
+ * }
173
+ * };
174
+ * const user2 = await classable.create(dbResolver, dbContext); // Type: Promise<User>
175
+ * ```
176
+ */
177
+ export interface AsyncClassableByResolver<InstanceType, Args extends Readonlyable<any[]> = [], Runtime = never> {
178
+ target: ClassType<InstanceType, [...Args]>;
179
+ resolve: (...args: Runtime extends never ? [] : [runtime: Runtime]) => Promise<Args>;
180
+ }
109
181
  /**
110
182
  * Union type representing either a direct class constructor or a resolver configuration.
111
183
  *
@@ -283,16 +355,18 @@ export interface ClassableAPI {
283
355
  type: "class" | "resolver";
284
356
  target: string;
285
357
  };
286
- /** Creates an instance from a plain class. */
358
+ /** Creates an instance from a plain class (no constructor arguments). */
287
359
  create<InstanceType>(cls: ClassType<InstanceType>): InstanceType;
288
- /** Creates an instance from a resolver with sync resolve function. */
289
- create<InstanceType, Args extends Readonlyable<any[]>, Runtime>(cls: ClassableByResolver<InstanceType, Args, Runtime> & {
290
- resolve: (runtime: Runtime) => Args;
291
- }, runtime: Runtime): InstanceType;
292
- /** Creates an instance from a resolver with async resolve function. */
293
- create<InstanceType, Args extends Readonlyable<any[]>, Runtime>(cls: ClassableByResolver<InstanceType, Args, Runtime> & {
294
- resolve: (runtime: Runtime) => Promise<Args>;
295
- }, runtime: Runtime): Promise<InstanceType>;
360
+ /** Creates an instance from a Classable (class or resolver) with no arguments. */
361
+ create<InstanceType>(cls: Classable<InstanceType, []>): InstanceType;
362
+ /** Creates an instance from a sync resolver without runtime context. */
363
+ create<InstanceType, Args extends Readonlyable<any[]>>(cls: SyncClassableByResolver<InstanceType, Args, never>): InstanceType;
364
+ /** Creates an instance from an async resolver without runtime context. */
365
+ create<InstanceType, Args extends Readonlyable<any[]>>(cls: AsyncClassableByResolver<InstanceType, Args, never>): Promise<InstanceType>;
366
+ /** Creates an instance from a sync resolver with runtime context. */
367
+ create<InstanceType, Args extends Readonlyable<any[]>, Runtime>(cls: SyncClassableByResolver<InstanceType, Args, Runtime>, runtime: Runtime): InstanceType;
368
+ /** Creates an instance from an async resolver with runtime context. */
369
+ create<InstanceType, Args extends Readonlyable<any[]>, Runtime>(cls: AsyncClassableByResolver<InstanceType, Args, Runtime>, runtime: Runtime): Promise<InstanceType>;
296
370
  /**
297
371
  * Creates an instance from a static factory method definition.
298
372
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mxweb/classable",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "A class-first abstraction for defining logic as resolvable units without runtime assumptions.",
5
5
  "license": "MIT",
6
6
  "keywords": [