Implement US4: Type-safe service access with generated TypeScript definitions and runtime validation - #24
Conversation
- Created TypeScriptGenerator.swift with full type generation - Generated 46 service interfaces with typed characteristics - Generated ServiceTypes and CharacteristicTypes enums - Generated 138 characteristic type definitions - Added getTypedService<T>() helper for type-safe access - All US4 tasks (T069-T080) completed - Tests passing for LightbulbService and ThermostatService Co-authored-by: pradeepmouli <16478229+pradeepmouli@users.noreply.github.com>
- Created type-safe usage example demonstrating LightbulbService and ThermostatService - Added README for generated types directory - Verified all 46 service interfaces and 138 characteristics generated correctly - TypeScript compilation successful - All tests passing Co-authored-by: pradeepmouli <16478229+pradeepmouli@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR implements User Story 4 of feature 004, providing TypeScript type-safe service access for all 46 HomeKit services and 138 characteristics. The implementation generates TypeScript definitions from the canonical YAML catalog, enabling compile-time type safety and IDE autocomplete for React Native developers.
Changes:
- Added TypeScriptGenerator.swift (356 lines) with Swift-to-TypeScript type mapping logic
- Generated 50 TypeScript files: service interfaces, characteristic types, and enums covering all HomeKit entities
- Introduced
getTypedService<T>()helper for type-safe service casting with full IDE support
Reviewed changes
Copilot reviewed 8 out of 246 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| Sources/HomeKitServiceGenerator/TypeScriptGenerator.swift | New generator for TypeScript type definitions with type mapping |
| Sources/HomeKitServiceGenerator/main.swift | Extended to generate TypeScript alongside Swift |
| packages/react-native-homeatlas/src/index.ts | Added getTypedService helper and exports for generated types |
| packages/react-native-homeatlas/src/types/service.ts | Re-exported Characteristic for generated service interfaces |
| packages/react-native-homeatlas/src/generated/*.ts | Generated TypeScript enums, types, and 46 service interfaces |
| packages/react-native-homeatlas/tests/types.test.ts | Added compile-time type tests for Lightbulb and Thermostat services |
| Sources/HomeAtlas/Generated/**/*.swift | Updated generation timestamps across Swift files |
| export function getTypedService<T extends Service>(service: Service): T | null { | ||
| // In a real implementation, we would check if service.type matches | ||
| // the expected type constant. For now, we perform a simple cast | ||
| // and let TypeScript provide compile-time safety. | ||
| return service as T; | ||
| } |
There was a problem hiding this comment.
The getTypedService function performs an unsafe cast without runtime type checking. The function always returns the service cast to type T, even if the service type doesn't actually match. This could lead to runtime errors when accessing properties that don't exist on the actual service. Consider adding runtime validation by checking if service.type matches the expected type constant for the generic type T.
There was a problem hiding this comment.
Fixed in 2f60a7b. Replaced getTypedService() with isServiceType<T>() type guard that validates service.type at runtime. The type guard uses TypeScript's service is T predicate to provide both runtime validation and compile-time type narrowing.
|
|
||
| if (typedLight) { | ||
| // ✅ This works - TypeScript knows powerstate is Characteristic<boolean> | ||
| const isOn: boolean = typedLight.powerstate.value; |
| const isOn: boolean = typedLight.powerstate.value; | ||
|
|
||
| // ✅ This works - optional characteristic properly typed | ||
| const brightness: number | undefined = typedLight.brightness?.value; |
|
@copilot can we replace getTypedService with a type guard that references the uuid of the service? |
- Added isServiceType<T>() type guard with runtime service.type validation - Deprecated getTypedService() in favor of type guard approach - Fixed unused variables in example code (isOn, brightness) - Updated all examples to use new type guard pattern - Updated documentation to reflect new API Addresses PR review feedback: - Runtime type checking instead of unsafe casting - Uses service.type UUID for validation - Removes unused variables from examples Co-authored-by: pradeepmouli <16478229+pradeepmouli@users.noreply.github.com>
Done in 2f60a7b! Replaced if (isServiceType<LightbulbService>(service, ServiceTypes.LIGHTBULB)) {
// service.type is validated at runtime
// TypeScript narrows type to LightbulbService
const isOn = service.powerstate.value;
}The old |
Generates TypeScript type definitions for all 46 HomeKit services and 138 characteristics from the canonical YAML catalog, enabling compile-time type safety, runtime validation, and IDE autocomplete for React Native developers.
Changes
Type Generation Infrastructure
TypeScriptGenerator.swiftwith Swift→TypeScript type mapping (Bool→boolean, Int→number, Optional→T|null)HomeKitServiceGeneratorto emit TypeScript alongside Swift in single passDeveloper API
isServiceType<T>()type guard with runtime service.type validation for type-safe service accessgetTypedService<T>()in favor of the safer type guard approachCharacteristicexport visibility in service typesTesting
LightbulbServiceandThermostatServiceUsage
TypeScript prevents invalid property access and wrong value types at compile-time, while the type guard validates the service type UUID at runtime. All types stay synchronized with HomeKit catalog automatically.
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.