Skip to content

Commit 988a195

Browse files
committed
Better types
1 parent 14a756b commit 988a195

File tree

2 files changed

+55
-21
lines changed

2 files changed

+55
-21
lines changed

packages/dataviews/src/types/field-api.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ export type DayString =
337337
| 'friday'
338338
| 'saturday';
339339

340-
export type NormalizedField< Item > = Omit< Field< Item >, 'Edit' > & {
340+
type NormalizedFieldBase< Item > = Omit< Field< Item >, 'Edit' > & {
341341
label: string;
342342
header: string | ReactElement;
343343
getValue: ( args: { item: Item } ) => any;
@@ -351,9 +351,22 @@ export type NormalizedField< Item > = Omit< Field< Item >, 'Edit' > & {
351351
enableSorting: boolean;
352352
filterBy: NormalizedFilterByConfig | false;
353353
readOnly: boolean;
354-
format: {} | Required< FormatDate >;
355354
};
356355

356+
type NormalizedFieldDate< Item > = NormalizedFieldBase< Item > & {
357+
type: 'date';
358+
format: Required< FormatDate >;
359+
};
360+
361+
type NormalizedFieldGeneric< Item > = NormalizedFieldBase< Item > & {
362+
type?: Exclude< FieldType, 'date' >;
363+
format: {};
364+
};
365+
366+
export type NormalizedField< Item > =
367+
| NormalizedFieldGeneric< Item >
368+
| NormalizedFieldDate< Item >;
369+
357370
/**
358371
* A collection of dataview fields for a data type.
359372
*/

packages/dataviews/src/utils/normalize-fields.ts

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -189,24 +189,22 @@ export default function normalizeFields< Item >(
189189

190190
const filterBy = getFilterBy( field, fieldTypeDefinition );
191191

192-
let format = {};
193-
if ( field.type === 'date' ) {
194-
format = {
195-
date:
196-
field.format?.date !== undefined &&
197-
typeof field.format.date === 'string'
198-
? field.format.date
199-
: getSettings().formats.date,
200-
weekStartsOn: DAYS_OF_WEEK.includes(
201-
field.format?.weekStartsOn as DayString
202-
)
203-
? field?.format?.weekStartsOn
204-
: numberToWeekStartsOn( getSettings().l10n.startOfWeek ),
205-
};
206-
}
207-
208-
return {
209-
...field,
192+
/**
193+
* NormalizedField is a discriminated union type: the shape of the format property
194+
* depends on the type property. For example, for the 'date' type, the format
195+
* contains date or weekStartsOn — which are not valid for other types.
196+
*
197+
* Being type and format interdependent, we need to write the code
198+
* in a way that TypeScript is able to statically infer the types.
199+
* That's why we have a return branch for every item in the union type.
200+
*
201+
* See a longer explanation with examples at
202+
* https://github.com/WordPress/gutenberg/pull/72999#discussion_r2523145453
203+
*/
204+
const { type, ...fieldWithoutType } = field;
205+
206+
const baseField = {
207+
...fieldWithoutType,
210208
label: field.label || field.id,
211209
header: field.header || field.label || field.id,
212210
getValue,
@@ -223,7 +221,30 @@ export default function normalizeFields< Item >(
223221
true,
224222
filterBy,
225223
readOnly: field.readOnly ?? fieldTypeDefinition.readOnly ?? false,
226-
format,
224+
format: {},
227225
};
226+
227+
if ( field.type === 'date' ) {
228+
const format = {
229+
date:
230+
field.format?.date !== undefined &&
231+
typeof field.format.date === 'string'
232+
? field.format.date
233+
: getSettings().formats.date,
234+
weekStartsOn: DAYS_OF_WEEK.includes(
235+
field.format?.weekStartsOn as DayString
236+
)
237+
? field?.format?.weekStartsOn
238+
: numberToWeekStartsOn( getSettings().l10n.startOfWeek ),
239+
};
240+
241+
return {
242+
...baseField,
243+
type: 'date',
244+
format,
245+
};
246+
}
247+
248+
return { ...baseField, type: field.type, format: {} };
228249
} );
229250
}

0 commit comments

Comments
 (0)