From 49748b5c7989b4e27686798ea7935e87d804eece Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 1 May 2026 10:10:41 +0200 Subject: [PATCH] fix(core): enforce return type for service factory Updates the `factory` signature in `@Service` to enforce the type of the returned value. --- goldens/public-api/core/index.api.md | 7 +++++-- packages/core/src/di/service.ts | 16 ++++++++++++---- packages/core/test/acceptance/service_spec.ts | 8 ++++---- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/goldens/public-api/core/index.api.md b/goldens/public-api/core/index.api.md index 52ebd1e6565..ea00d617e1e 100644 --- a/goldens/public-api/core/index.api.md +++ b/goldens/public-api/core/index.api.md @@ -1802,12 +1802,15 @@ export const Service: ServiceDecorator; // @public export interface ServiceDecorator { (): TypeDecorator; - (options?: { + (options: { autoProvided: false; }): TypeDecorator; + (options: { + autoProvided?: true; + factory: () => T; + }): >(target: C) => Type; (options?: { autoProvided?: true; - factory?: () => unknown; }): TypeDecorator; } diff --git a/packages/core/src/di/service.ts b/packages/core/src/di/service.ts index 14f53f9d0a8..3588d5dfc41 100644 --- a/packages/core/src/di/service.ts +++ b/packages/core/src/di/service.ts @@ -30,13 +30,21 @@ export interface ServiceDecorator { * When `autoProvided` is set to `false`, the service won't be exposed to the dependency * injection system automatically. It is up to the user to expose it in a providers list. */ - (options?: {autoProvided: false}): TypeDecorator; + (options: {autoProvided: false}): TypeDecorator; /** - * Creates a service that is automatically provided. Passing an optional - * `factory` allows for the runtime value to be replaced. + * Creates a service that is automatically provided and uses + * the value returned from the `factory` function. */ - (options?: {autoProvided?: true; factory?: () => unknown}): TypeDecorator; + (options: { + autoProvided?: true; + factory: () => T; + }): >(target: C) => Type; + + /** + * Creates a service that is automatically provided. + */ + (options?: {autoProvided?: true}): TypeDecorator; } /** diff --git a/packages/core/test/acceptance/service_spec.ts b/packages/core/test/acceptance/service_spec.ts index d2200f81de4..af931481869 100644 --- a/packages/core/test/acceptance/service_spec.ts +++ b/packages/core/test/acceptance/service_spec.ts @@ -28,7 +28,7 @@ describe('@Service decorator', () => { it('should be able to provide an alternate implementation using `factory`', () => { @Service({factory: () => ({value: 'alternate'})}) class MyService { - readonly value = 'MyService'; + value = 'MyService'; } @Component({template: ''}) @@ -43,7 +43,7 @@ describe('@Service decorator', () => { it('should be able to provide an alternate implementation using `factory` when `autoProvided` is set to true', () => { @Service({autoProvided: true, factory: () => ({value: 'alternate'})}) class MyService { - readonly value = 'MyService'; + value = 'MyService'; } @Component({template: ''}) @@ -60,7 +60,7 @@ describe('@Service decorator', () => { @Service({factory: () => ({value: inject(token)})}) class MyService { - readonly value = 'MyService'; + value = 'MyService'; } @Component({template: ''}) @@ -153,7 +153,7 @@ describe('@Service decorator', () => { it('should be able to override a service that has a factory', () => { @Service({factory: () => ({value: 'factory'})}) class MyService { - readonly value = 'MyService'; + value = 'MyService'; } @Service()