Skip to content

Commit 2c52b9c

Browse files
authored
Merge pull request #493 from ForgeRock/update-type-exports
chore: type-exports
2 parents abc449e + b160ecd commit 2c52b9c

File tree

14 files changed

+401
-24
lines changed

14 files changed

+401
-24
lines changed

e2e/davinci-app/components/multi-value.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import type { MultiSelectCollector, Updater } from '@forgerock/davinci-client/ty
1616
export default function multiValueComponent(
1717
formEl: HTMLFormElement,
1818
collector: MultiSelectCollector,
19-
updater: Updater,
19+
updater: Updater<MultiSelectCollector>,
2020
) {
2121
// Create a container for the checkboxes
2222
const containerDiv = document.createElement('div');

e2e/davinci-app/components/object-value.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ import type {
2020
export default function objectValueComponent(
2121
formEl: HTMLFormElement,
2222
collector: DeviceRegistrationCollector | DeviceAuthenticationCollector | PhoneNumberCollector,
23-
updater: Updater,
23+
updater:
24+
| Updater<DeviceRegistrationCollector>
25+
| Updater<DeviceAuthenticationCollector>
26+
| Updater<PhoneNumberCollector>,
2427
submitForm: () => void,
2528
) {
2629
if (
@@ -50,7 +53,7 @@ export default function objectValueComponent(
5053
console.error('No value found for the selected option');
5154
return;
5255
}
53-
updater(selectedValue);
56+
updater(selectedValue as any);
5457
submitForm();
5558
});
5659

@@ -84,7 +87,7 @@ export default function objectValueComponent(
8487
updater({
8588
phoneNumber: selectedValue,
8689
countryCode: collector.output.value?.countryCode || '',
87-
});
90+
} as any);
8891
});
8992

9093
formEl.appendChild(phoneLabel);

e2e/davinci-app/components/password.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { dotToCamelCase } from '../helper.js';
1010
export default function passwordComponent(
1111
formEl: HTMLFormElement,
1212
collector: PasswordCollector,
13-
updater: Updater,
13+
updater: Updater<PasswordCollector>,
1414
) {
1515
const label = document.createElement('label');
1616
const input = document.createElement('input');

e2e/davinci-app/components/protect.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type {
1313
export default function protectComponent(
1414
formEl: HTMLFormElement,
1515
collector: TextCollector | ValidatedTextCollector,
16-
updater: Updater,
16+
updater: Updater<TextCollector | ValidatedTextCollector>,
1717
) {
1818
// create paragraph element with text of "Loading ... "
1919
const p = document.createElement('p');

e2e/davinci-app/components/single-value.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type { SingleSelectCollector, Updater } from '@forgerock/davinci-client/t
1515
export default function singleValueComponent(
1616
formEl: HTMLFormElement,
1717
collector: SingleSelectCollector,
18-
updater: Updater,
18+
updater: Updater<SingleSelectCollector>,
1919
) {
2020
// Create the label element
2121
const labelEl = document.createElement('label');

e2e/davinci-app/components/text.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { dotToCamelCase } from '../helper.js';
1515
export default function textComponent(
1616
formEl: HTMLFormElement,
1717
collector: TextCollector | ValidatedTextCollector,
18-
updater: Updater,
18+
updater: Updater<TextCollector | ValidatedTextCollector>,
1919
validator: Validator,
2020
) {
2121
const collectorKey = dotToCamelCase(collector.output.key);

packages/davinci-client/src/lib/client.store.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,13 +234,15 @@ export async function davinci<ActionType extends ActionTypes = ActionTypes>({
234234
* @param {SingleValueCollector | MultiSelectCollector | ObjectValueCollectors | AutoCollectors} collector - the collector to update
235235
* @returns {function} - a function to call for updating collector value
236236
*/
237-
update: (
238-
collector:
237+
update: <
238+
T extends
239239
| SingleValueCollectors
240240
| MultiSelectCollector
241241
| ObjectValueCollectors
242242
| AutoCollectors,
243-
): Updater => {
243+
>(
244+
collector: T,
245+
): Updater<T> => {
244246
if (!collector.id) {
245247
return handleUpdateValidateError(
246248
'Argument for `collector` has no ID',

packages/davinci-client/src/lib/client.types.ts

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,62 @@ export interface InternalErrorResponse {
2222

2323
export type InitFlow = () => Promise<FlowNode | InternalErrorResponse>;
2424

25-
export type Updater = (
26-
value:
27-
| string
28-
| string[]
29-
| PhoneNumberInputValue
30-
| FidoRegistrationInputValue
31-
| FidoAuthenticationInputValue,
25+
/**
26+
* Maps collector types to the specific value type they accept.
27+
* This enables type narrowing when using the update method with specific collector types.
28+
*
29+
* @example
30+
* ```typescript
31+
* if (collector.type === "PasswordCollector") {
32+
* const updater = davinciClient.update(collector);
33+
* // updater now only accepts: (value: string, index?: number) => ...
34+
* }
35+
* ```
36+
*/
37+
export type CollectorValueType<T> = T extends { type: 'PasswordCollector' }
38+
? string
39+
: T extends { type: 'TextCollector'; category: 'SingleValueCollector' }
40+
? string
41+
: T extends { type: 'TextCollector'; category: 'ValidatedSingleValueCollector' }
42+
? string
43+
: T extends { type: 'SingleSelectCollector' }
44+
? string
45+
: T extends { type: 'MultiSelectCollector' }
46+
? string[]
47+
: T extends { type: 'DeviceRegistrationCollector' }
48+
? string
49+
: T extends { type: 'DeviceAuthenticationCollector' }
50+
? string
51+
: T extends { type: 'PhoneNumberCollector' }
52+
? PhoneNumberInputValue
53+
: T extends { type: 'FidoRegistrationCollector' }
54+
? FidoRegistrationInputValue
55+
: T extends { type: 'FidoAuthenticationCollector' }
56+
? FidoAuthenticationInputValue
57+
: T extends { category: 'SingleValueCollector' }
58+
? string
59+
: T extends { category: 'ValidatedSingleValueCollector' }
60+
? string
61+
: T extends { category: 'MultiValueCollector' }
62+
? string[]
63+
:
64+
| string
65+
| string[]
66+
| PhoneNumberInputValue
67+
| FidoRegistrationInputValue
68+
| FidoAuthenticationInputValue;
69+
70+
/**
71+
* Generic updater function that accepts values appropriate for the collector type.
72+
* When used with type narrowing, the value parameter will be constrained to the correct type.
73+
*
74+
* @template T The collector type (inferred from the collector passed to update())
75+
* @param value The value to update the collector with (type depends on T)
76+
* @param index Optional index for multi-value collectors
77+
* @returns null on success, or an InternalErrorResponse on failure
78+
*/
79+
export type Updater<T = unknown> = (
80+
value: CollectorValueType<T>,
3281
index?: number,
3382
) => InternalErrorResponse | null;
3483
export type Validator = (value: string) =>

0 commit comments

Comments
 (0)