Skip to content

Commit 4b58de4

Browse files
committed
fix(core): improve resource generics and params typing
Allow single generic usage when params are not defined and prevent accessing params in loader when not provided. - remove the test cases from resource_specs
1 parent 3ac0d90 commit 4b58de4

File tree

6 files changed

+42
-52
lines changed

6 files changed

+42
-52
lines changed

goldens/public-api/core/index.api.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,21 +1642,21 @@ export function resource<T, R>(options: ResourceOptionsWithRequiredLoader<T, R>
16421642
}): ResourceRef<T>;
16431643

16441644
// @public (undocumented)
1645-
export function resource<T>(options: ResourceOptionsWithOptionalLoader<T, unknown> & {
1645+
export function resource<T>(options: ResourceOptionsWithOptionalLoader<T, never> & {
16461646
defaultValue: NoInfer<T>;
16471647
}): ResourceRef<T>;
16481648

16491649
// @public (undocumented)
16501650
export function resource<T, R>(options: ResourceOptionsWithRequiredLoader<T, R>): ResourceRef<T | undefined>;
16511651

16521652
// @public (undocumented)
1653-
export function resource<T>(options: ResourceOptionsWithOptionalLoader<T, unknown>): ResourceRef<T | undefined>;
1653+
export function resource<T>(options: ResourceOptionsWithOptionalLoader<T, never>): ResourceRef<T | undefined>;
16541654

16551655
// @public (undocumented)
1656-
export function resource<T, R>(options: ResourceOptions<T, R>): ResourceRef<T | undefined>;
1656+
export function resource<T, R = never>(options: ResourceOptionsWithOptionalLoader<T, R>): ResourceRef<T | undefined>;
16571657

16581658
// @public (undocumented)
1659-
export function resource<T, R = never>(options: ResourceOptionsWithOptionalLoader<T, R>): ResourceRef<T | undefined>;
1659+
export function resource<T, R>(options: ResourceOptions<T, R>): ResourceRef<T | undefined>;
16601660

16611661
// @public
16621662
export class ResourceDependencyError extends Error {

goldens/public-api/core/rxjs-interop/index.api.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,24 @@ export function rxResource<T, R>(opts: ResourceOptionsWithRequiredParams<T, R> &
3131

3232
// @public (undocumented)
3333
export function rxResource<T>(opts: ResourceOptionsWithOptionalParams<T, never> & {
34-
stream: (params: SafeLoaderParams<never>) => Observable<T>;
34+
stream: (params: SafeLoaderParams<null>) => Observable<T>;
3535
defaultValue: NoInfer<T>;
3636
}): ResourceRef<T>;
3737

3838
// @public (undocumented)
3939
export function rxResource<T>(opts: ResourceOptionsWithOptionalParams<T, never> & {
40-
stream: (params: SafeLoaderParams<never>) => Observable<T>;
40+
stream: (params: SafeLoaderParams<null>) => Observable<T>;
41+
}): ResourceRef<T | undefined>;
42+
43+
// @public (undocumented)
44+
export function rxResource<T, R>(opts: ResourceOptionsWithOptionalParams<T, R> & {
45+
stream: (params: SafeLoaderParams<Exclude<R, undefined> | null>) => Observable<T>;
46+
defaultValue: NoInfer<T>;
47+
}): ResourceRef<T>;
48+
49+
// @public (undocumented)
50+
export function rxResource<T, R>(opts: ResourceOptionsWithOptionalParams<T, R> & {
51+
stream: (params: SafeLoaderParams<Exclude<R, undefined> | null>) => Observable<T>;
4152
}): ResourceRef<T | undefined>;
4253

4354
// @public

packages/core/rxjs-interop/src/rx_resource.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,31 @@ export function rxResource<T, R>(
5959
},
6060
): ResourceRef<T | undefined>;
6161

62-
// Overload B: no params → loader cannot access params
62+
// Overload B: no params → loader receives params: null at runtime
6363
export function rxResource<T>(
6464
opts: ResourceOptionsWithOptionalParams<T, never> & {
65-
stream: (params: SafeLoaderParams<never>) => Observable<T>;
65+
stream: (params: SafeLoaderParams<null>) => Observable<T>;
6666
defaultValue: NoInfer<T>;
6767
},
6868
): ResourceRef<T>;
6969

7070
export function rxResource<T>(
7171
opts: ResourceOptionsWithOptionalParams<T, never> & {
72-
stream: (params: SafeLoaderParams<never>) => Observable<T>;
72+
stream: (params: SafeLoaderParams<null>) => Observable<T>;
73+
},
74+
): ResourceRef<T | undefined>;
75+
76+
// Overload C: params is optionally typed (e.g. (() => R) | undefined) → stream receives R | null
77+
export function rxResource<T, R>(
78+
opts: ResourceOptionsWithOptionalParams<T, R> & {
79+
stream: (params: SafeLoaderParams<Exclude<R, undefined> | null>) => Observable<T>;
80+
defaultValue: NoInfer<T>;
81+
},
82+
): ResourceRef<T>;
83+
84+
export function rxResource<T, R>(
85+
opts: ResourceOptionsWithOptionalParams<T, R> & {
86+
stream: (params: SafeLoaderParams<Exclude<R, undefined> | null>) => Observable<T>;
7387
},
7488
): ResourceRef<T | undefined>;
7589

@@ -117,7 +131,7 @@ export function rxResource<T, R>(opts: RxResourceOptions<T, R>): ResourceRef<T |
117131
}
118132

119133
sub = streamFn(params as SafeLoaderParams<R>).subscribe({
120-
next: (value) => send({value}),
134+
next: (value: T) => send({value}),
121135
error: (error: unknown) => {
122136
send({error: encapsulateResourceError(error)});
123137
params.abortSignal.removeEventListener('abort', onAbort);

packages/core/src/resource/resource.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export function resource<T, R>(
7272

7373
// WITHOUT params + defaultValue
7474
export function resource<T>(
75-
options: ResourceOptionsWithOptionalLoader<T, unknown> & {defaultValue: NoInfer<T>},
75+
options: ResourceOptionsWithOptionalLoader<T, never> & {defaultValue: NoInfer<T>},
7676
): ResourceRef<T>;
7777

7878
// WITH params (no defaultValue)
@@ -82,15 +82,16 @@ export function resource<T, R>(
8282

8383
// WITHOUT params (no defaultValue)
8484
export function resource<T>(
85-
options: ResourceOptionsWithOptionalLoader<T, unknown>,
85+
options: ResourceOptionsWithOptionalLoader<T, never>,
8686
): ResourceRef<T | undefined>;
8787

88-
// FALLBACK (CRITICAL)
89-
export function resource<T, R>(options: ResourceOptions<T, R>): ResourceRef<T | undefined>;
90-
88+
// WITH optional params (no defaultValue) — params omitted or undefined: loader receives null
9189
export function resource<T, R = never>(
9290
options: ResourceOptionsWithOptionalLoader<T, R>,
9391
): ResourceRef<T | undefined>;
92+
93+
// FALLBACK
94+
export function resource<T, R>(options: ResourceOptions<T, R>): ResourceRef<T | undefined>;
9495
export function resource<T, R>(options: ResourceOptions<T, R>): ResourceRef<T | undefined> {
9596
if (ngDevMode && !options?.injector) {
9697
assertInInjectionContext(resource);

packages/core/src/resource/resource_option_types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import {BaseResourceOptions, ResourceParamsContext} from './api';
1010

1111
export type ResourceOptionsWithRequiredParams<T, R> = Omit<BaseResourceOptions<T, R>, 'params'> & {
12-
params?: (ctx: ResourceParamsContext) => R;
12+
params: (ctx: ResourceParamsContext) => R;
1313
};
1414

1515
export type ResourceOptionsWithoutParams<T> = Omit<BaseResourceOptions<T, never>, 'params'> & {

packages/core/test/resource/resource_spec.ts

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -944,42 +944,6 @@ describe('resource', () => {
944944
});
945945

946946
describe('types', () => {
947-
it('should type loader params as nullable when params are omitted', () => {
948-
resource<string, string>({
949-
loader: async ({params}) => {
950-
const _nullable: string | null = params;
951-
const _nonNullable: string = params;
952-
return '';
953-
},
954-
injector: TestBed.inject(Injector),
955-
});
956-
});
957-
958-
it('should type loader params as nullable when params is undefined', () => {
959-
resource<string, string>({
960-
params: undefined,
961-
loader: async ({params}) => {
962-
const _nullable: string | null = params;
963-
const _nonNullable: string = params;
964-
return '';
965-
},
966-
injector: TestBed.inject(Injector),
967-
});
968-
});
969-
970-
it('should keep loader params non-nullable when params is provided', () => {
971-
resource<string, string | undefined>({
972-
params: () => 'foo',
973-
loader: async ({params}) => {
974-
const _nonNullable: string = params;
975-
// @ts-expect-error
976-
const _nullableOnly: null = params;
977-
return '';
978-
},
979-
injector: TestBed.inject(Injector),
980-
});
981-
});
982-
983947
it('should narrow hasValue() when the value can be undefined', () => {
984948
const result: ResourceRef<number | undefined> = resource({
985949
params: () => 1,

0 commit comments

Comments
 (0)