objcjs-types 0.6.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -108,6 +108,39 @@ if (isKindOfClass<_ASAuthorizationAppleIDCredential>(cred, ASAuthorizationAppleI
108
108
 
109
109
  Both `instanceof` and `isKindOfClass` cache results per (object, class) pair so repeated checks skip the native boundary.
110
110
 
111
+ ### Subclassing
112
+
113
+ `defineSubclass` wraps `NobjcClass.define()` with type safety — `self` is typed as the superclass, protocol method names get autocomplete, and the returned class supports `alloc`/`init` and `instanceof`:
114
+
115
+ ```ts
116
+ import { NSObject } from "objcjs-types/Foundation";
117
+ import { defineSubclass, callSuper } from "objcjs-types/subclass";
118
+
119
+ const MyDelegate = defineSubclass(NSObject, {
120
+ name: "MyDelegate",
121
+ protocols: ["NSWindowDelegate"],
122
+ methods: {
123
+ windowDidResize$: {
124
+ types: "v@:@",
125
+ implementation(self, notification) {
126
+ console.log("Resized!");
127
+ }
128
+ },
129
+ init: {
130
+ types: "@@:",
131
+ implementation(self) {
132
+ return callSuper(self, "init");
133
+ }
134
+ }
135
+ }
136
+ });
137
+
138
+ const instance = MyDelegate.alloc().init();
139
+ window.setDelegate$(instance);
140
+ ```
141
+
142
+ Use `callSuper` inside method implementations to invoke the superclass version of a method.
143
+
111
144
  ### NS_OPTIONS
112
145
 
113
146
  Use `options()` to combine bitmask flags with type safety:
@@ -175,14 +208,15 @@ const nsStr = NSStringFromString("hello");
175
208
 
176
209
  ## Subpath exports
177
210
 
178
- | Import path | Contents |
179
- | -------------------------- | ------------------------------------------------------ |
180
- | `objcjs-types` | Structs, `createDelegate`, barrel re-exports |
181
- | `objcjs-types/helpers` | `NSStringFromString`, `options`, `isKindOfClass`, etc. |
182
- | `objcjs-types/nsdata` | NSData/Buffer conversion utilities |
183
- | `objcjs-types/osversion` | macOS version detection and comparison |
184
- | `objcjs-types/delegates` | `createDelegate` and `ProtocolMap` type |
185
- | `objcjs-types/<Framework>` | Framework exports (e.g. `objcjs-types/AppKit`) |
211
+ | Import path | Contents |
212
+ | -------------------------- | -------------------------------------------------------- |
213
+ | `objcjs-types` | Structs, `createDelegate`, `defineSubclass`, `callSuper` |
214
+ | `objcjs-types/helpers` | `NSStringFromString`, `options`, `isKindOfClass`, etc. |
215
+ | `objcjs-types/subclass` | `defineSubclass`, `callSuper` |
216
+ | `objcjs-types/nsdata` | NSData/Buffer conversion utilities |
217
+ | `objcjs-types/osversion` | macOS version detection and comparison |
218
+ | `objcjs-types/delegates` | `createDelegate` and `ProtocolMap` type |
219
+ | `objcjs-types/<Framework>` | Framework exports (e.g. `objcjs-types/AppKit`) |
186
220
 
187
221
  ## ObjC selector naming
188
222
 
@@ -10,6 +10,17 @@ import type { NobjcObject } from "objc-js";
10
10
  import type { ProtocolMap } from "./delegates.js";
11
11
  /** Converts a union type to an intersection type. */
12
12
  type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
13
+ /**
14
+ * Extracts only explicitly declared (non-index-signature) string keys from a type.
15
+ *
16
+ * Generated ObjC classes extend `NobjcObject` which has `[key: string]: NobjcMethod`.
17
+ * Plain `keyof T` includes `string` from that index signature, defeating autocomplete
18
+ * and generic key constraints. This type filters it out, keeping only the known
19
+ * literal method names like `"init"`, `"description"`, `"setTitle$"`, etc.
20
+ */
21
+ type DeclaredKeys<T> = Extract<keyof {
22
+ [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K];
23
+ }, string>;
13
24
  /**
14
25
  * A method definition for a subclass.
15
26
  *
@@ -42,14 +53,12 @@ type ProtocolMethodKeys<TProtocols extends keyof ProtocolMap> = Extract<keyof Un
42
53
  /**
43
54
  * Methods record for a subclass definition.
44
55
  *
45
- * Provides autocomplete for method names from the specified protocols
46
- * while allowing arbitrary method names for custom methods or
47
- * superclass overrides.
56
+ * Provides autocomplete for method names from the superclass and any
57
+ * specified protocols, while still allowing arbitrary method names for
58
+ * custom methods via `(string & {})`.
48
59
  */
49
60
  type SubclassMethods<TSelf, TProtocols extends keyof ProtocolMap> = {
50
- [key: string]: SubclassMethodDef<TSelf> | undefined;
51
- } & {
52
- [K in ProtocolMethodKeys<TProtocols>]?: SubclassMethodDef<TSelf>;
61
+ [K in ProtocolMethodKeys<TProtocols> | DeclaredKeys<TSelf> | (string & {})]?: SubclassMethodDef<TSelf>;
53
62
  };
54
63
  /**
55
64
  * Define a new Objective-C subclass at runtime with TypeScript type safety.
@@ -103,20 +112,27 @@ export declare function defineSubclass<TClass extends abstract new (...args: any
103
112
  * Call the superclass implementation of a method from within a subclass
104
113
  * method implementation.
105
114
  *
115
+ * The selector is constrained to method names on the `self` type, giving
116
+ * autocomplete and validating that a super implementation exists. Arguments
117
+ * and return type are inferred from the superclass method signature.
118
+ *
119
+ * For dynamic selectors not known at compile time, use `NobjcClass.super()`
120
+ * from `objc-js` directly.
121
+ *
106
122
  * @param self - The instance (`self`, the first argument of your implementation)
107
- * @param selector - The method selector (e.g. `"init"`, `"viewDidLoad"`)
108
- * @param args - Arguments to forward to the super implementation
109
- * @returns The result of the super call
123
+ * @param selector - The method name to call on super (e.g. `"init"`, `"viewDidLoad"`)
124
+ * @param args - Arguments matching the superclass method's parameter types
125
+ * @returns The return type of the superclass method
110
126
  *
111
127
  * @example
112
128
  * ```ts
113
129
  * init: {
114
130
  * types: "@@:",
115
131
  * implementation(self) {
116
- * return callSuper(self, "init");
132
+ * return callSuper(self, "init"); // returns _NSObject
117
133
  * },
118
134
  * }
119
135
  * ```
120
136
  */
121
- export declare function callSuper(self: NobjcObject, selector: string, ...args: unknown[]): any;
137
+ export declare function callSuper<TSelf, K extends DeclaredKeys<TSelf>>(self: TSelf, selector: K, ...args: TSelf[K] extends (...a: infer A) => any ? A : any[]): TSelf[K] extends (...a: any[]) => infer R ? R : any;
122
138
  export {};
package/dist/subclass.js CHANGED
@@ -79,17 +79,24 @@ export function defineSubclass(superclass, definition) {
79
79
  * Call the superclass implementation of a method from within a subclass
80
80
  * method implementation.
81
81
  *
82
+ * The selector is constrained to method names on the `self` type, giving
83
+ * autocomplete and validating that a super implementation exists. Arguments
84
+ * and return type are inferred from the superclass method signature.
85
+ *
86
+ * For dynamic selectors not known at compile time, use `NobjcClass.super()`
87
+ * from `objc-js` directly.
88
+ *
82
89
  * @param self - The instance (`self`, the first argument of your implementation)
83
- * @param selector - The method selector (e.g. `"init"`, `"viewDidLoad"`)
84
- * @param args - Arguments to forward to the super implementation
85
- * @returns The result of the super call
90
+ * @param selector - The method name to call on super (e.g. `"init"`, `"viewDidLoad"`)
91
+ * @param args - Arguments matching the superclass method's parameter types
92
+ * @returns The return type of the superclass method
86
93
  *
87
94
  * @example
88
95
  * ```ts
89
96
  * init: {
90
97
  * types: "@@:",
91
98
  * implementation(self) {
92
- * return callSuper(self, "init");
99
+ * return callSuper(self, "init"); // returns _NSObject
93
100
  * },
94
101
  * }
95
102
  * ```
@@ -15,6 +15,19 @@ import type { ProtocolMap } from "./delegates.js";
15
15
  /** Converts a union type to an intersection type. */
16
16
  type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
17
17
 
18
+ /**
19
+ * Extracts only explicitly declared (non-index-signature) string keys from a type.
20
+ *
21
+ * Generated ObjC classes extend `NobjcObject` which has `[key: string]: NobjcMethod`.
22
+ * Plain `keyof T` includes `string` from that index signature, defeating autocomplete
23
+ * and generic key constraints. This type filters it out, keeping only the known
24
+ * literal method names like `"init"`, `"description"`, `"setTitle$"`, etc.
25
+ */
26
+ type DeclaredKeys<T> = Extract<
27
+ keyof { [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K] },
28
+ string
29
+ >;
30
+
18
31
  /**
19
32
  * A method definition for a subclass.
20
33
  *
@@ -52,13 +65,13 @@ type ProtocolMethodKeys<TProtocols extends keyof ProtocolMap> = Extract<
52
65
  /**
53
66
  * Methods record for a subclass definition.
54
67
  *
55
- * Provides autocomplete for method names from the specified protocols
56
- * while allowing arbitrary method names for custom methods or
57
- * superclass overrides.
68
+ * Provides autocomplete for method names from the superclass and any
69
+ * specified protocols, while still allowing arbitrary method names for
70
+ * custom methods via `(string & {})`.
58
71
  */
59
72
  type SubclassMethods<TSelf, TProtocols extends keyof ProtocolMap> = {
60
- [key: string]: SubclassMethodDef<TSelf> | undefined;
61
- } & { [K in ProtocolMethodKeys<TProtocols>]?: SubclassMethodDef<TSelf> };
73
+ [K in ProtocolMethodKeys<TProtocols> | DeclaredKeys<TSelf> | (string & {})]?: SubclassMethodDef<TSelf>;
74
+ };
62
75
 
63
76
  /**
64
77
  * Define a new Objective-C subclass at runtime with TypeScript type safety.
@@ -150,21 +163,32 @@ export function defineSubclass<
150
163
  * Call the superclass implementation of a method from within a subclass
151
164
  * method implementation.
152
165
  *
166
+ * The selector is constrained to method names on the `self` type, giving
167
+ * autocomplete and validating that a super implementation exists. Arguments
168
+ * and return type are inferred from the superclass method signature.
169
+ *
170
+ * For dynamic selectors not known at compile time, use `NobjcClass.super()`
171
+ * from `objc-js` directly.
172
+ *
153
173
  * @param self - The instance (`self`, the first argument of your implementation)
154
- * @param selector - The method selector (e.g. `"init"`, `"viewDidLoad"`)
155
- * @param args - Arguments to forward to the super implementation
156
- * @returns The result of the super call
174
+ * @param selector - The method name to call on super (e.g. `"init"`, `"viewDidLoad"`)
175
+ * @param args - Arguments matching the superclass method's parameter types
176
+ * @returns The return type of the superclass method
157
177
  *
158
178
  * @example
159
179
  * ```ts
160
180
  * init: {
161
181
  * types: "@@:",
162
182
  * implementation(self) {
163
- * return callSuper(self, "init");
183
+ * return callSuper(self, "init"); // returns _NSObject
164
184
  * },
165
185
  * }
166
186
  * ```
167
187
  */
168
- export function callSuper(self: NobjcObject, selector: string, ...args: unknown[]): any {
169
- return NobjcClass.super(self, selector, ...args);
188
+ export function callSuper<TSelf, K extends DeclaredKeys<TSelf>>(
189
+ self: TSelf,
190
+ selector: K,
191
+ ...args: TSelf[K] extends (...a: infer A) => any ? A : any[]
192
+ ): TSelf[K] extends (...a: any[]) => infer R ? R : any {
193
+ return NobjcClass.super(self as any, selector as string, ...args);
170
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "objcjs-types",
3
- "version": "0.6.3",
3
+ "version": "0.7.0",
4
4
  "description": "Auto-generated TypeScript type declarations for macOS Objective-C frameworks that supplement objc-js",
5
5
  "type": "module",
6
6
  "sideEffects": false,