Skip to content

Commit fc2ea65

Browse files
r-farkhutdinovRuslan Farkhutdinov
andauthored
RadioGroup: Improve types (#33497)
Co-authored-by: Ruslan Farkhutdinov <ruslan.farkhutdinov@devexpress.com>
1 parent 3ac167f commit fc2ea65

3 files changed

Lines changed: 83 additions & 81 deletions

File tree

packages/devextreme/js/__internal/ui/radio_group/m_radio_button.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { dxElementWrapper } from '@js/core/renderer';
88
import $ from '@js/core/renderer';
99
import type { DxEvent } from '@js/events';
1010
import type { OptionChanged } from '@ts/core/widget/types';
11-
import type { EditorProperties } from '@ts/ui/editor/editor';
11+
import type { EditorProperties, ValueChangedEvent } from '@ts/ui/editor/editor';
1212
import Editor from '@ts/ui/editor/editor';
1313

1414
const RADIO_BUTTON_CLASS = 'dx-radiobutton';
@@ -24,11 +24,10 @@ class RadioButton extends Editor {
2424

2525
_clickAction?: (event?: Record<string, unknown>) => void;
2626

27-
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
28-
_supportedKeys(): Record<string, (e: KeyboardEvent) => void | boolean> {
29-
const click = function (e) {
27+
_supportedKeys(): Record<string, (e: KeyboardEvent) => void> {
28+
const click = (e: KeyboardEvent): void => {
3029
e.preventDefault();
31-
this._clickAction({ event: e });
30+
this._clickAction?.({ event: e });
3231
};
3332
return {
3433
...super._supportedKeys(),
@@ -70,10 +69,12 @@ class RadioButton extends Editor {
7069
}
7170

7271
_initMarkup(): void {
72+
const { value } = this.option();
73+
7374
super._initMarkup();
7475

7576
this._renderIcon();
76-
this._renderCheckedState(this.option('value'));
77+
this._renderCheckedState(value);
7778
this._renderClick();
7879
this.setAria('role', 'radio');
7980
}
@@ -85,7 +86,7 @@ class RadioButton extends Editor {
8586
this.$element().append(this._$icon);
8687
}
8788

88-
_renderCheckedState(checked): void {
89+
_renderCheckedState(checked: boolean): void {
8990
this.$element()
9091
.toggleClass(RADIO_BUTTON_CHECKED_CLASS, checked)
9192
.find(`.${RADIO_BUTTON_ICON_CLASS}`)
@@ -94,10 +95,9 @@ class RadioButton extends Editor {
9495
}
9596

9697
_renderClick(): void {
97-
// @ts-expect-error ts-error
98-
const eventName = addNamespace(clickEventName, this.NAME);
98+
const eventName = addNamespace(clickEventName, this.NAME ?? '');
9999

100-
this._clickAction = this._createAction((args): void => {
100+
this._clickAction = this._createAction((args: { event: ValueChangedEvent }): void => {
101101
this._clickHandler(args.event);
102102
});
103103

@@ -107,7 +107,7 @@ class RadioButton extends Editor {
107107
});
108108
}
109109

110-
_clickHandler(e): void {
110+
_clickHandler(e: ValueChangedEvent): void {
111111
this._saveValueChangeEvent(e);
112112
this.option('value', true);
113113
this._saveValueChangeEvent(undefined);

packages/devextreme/js/__internal/ui/radio_group/m_radio_collection.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { dxElementWrapper } from '@js/core/renderer';
22
import $ from '@js/core/renderer';
33
import { deferRender } from '@js/core/utils/common';
4-
import { extend } from '@js/core/utils/extend';
4+
import type { DxEvent } from '@js/events';
55
import DataExpressionMixin from '@js/ui/editor/ui.data_expression';
66
import type { CollectionWidgetBaseProperties } from '@ts/ui/collection/collection_widget.base';
77
import CollectionWidget from '@ts/ui/collection/collection_widget.edit';
@@ -26,12 +26,13 @@ class RadioCollection extends CollectionWidget<Properties> {
2626
}
2727

2828
_getDefaultOptions(): Properties {
29-
const defaultOptions = super._getDefaultOptions();
30-
31-
// @ts-expect-error
32-
return extend(defaultOptions, DataExpressionMixin._dataExpressionDefaultOptions(), {
29+
return {
30+
...super._getDefaultOptions(),
31+
// @ts-expect-error DataExpressionMixin._dataExpressionDefaultOptions()
32+
// should be added to the type
33+
...DataExpressionMixin._dataExpressionDefaultOptions(),
3334
_itemAttributes: { role: 'radio' },
34-
});
35+
} as Properties;
3536
}
3637

3738
_initMarkup(): void {
@@ -83,22 +84,21 @@ class RadioCollection extends CollectionWidget<Properties> {
8384
this._renderContent();
8485
}
8586

86-
_supportedKeys(): Record<string, (e: KeyboardEvent) => void> {
87+
_supportedKeys(): Record<string, (e: DxEvent<KeyboardEvent>) => void> {
8788
const parent = super._supportedKeys();
8889

89-
return extend({}, parent, {
90-
enter(e) {
90+
return {
91+
...parent,
92+
enter(e: DxEvent<KeyboardEvent>): void {
9193
e.preventDefault();
92-
// @ts-expect-error
93-
return parent.enter.apply(this, arguments);
94+
parent.enter?.apply(this, [e]);
9495
},
9596

96-
space(e) {
97+
space(e: DxEvent<KeyboardEvent>): void {
9798
e.preventDefault();
98-
// @ts-expect-error
99-
return parent.space.apply(this, arguments);
99+
parent.space?.apply(this, [e]);
100100
},
101-
});
101+
};
102102
}
103103

104104
_itemElements(): dxElementWrapper {

packages/devextreme/js/__internal/ui/radio_group/m_radio_group.ts

Lines changed: 57 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import type { dxElementWrapper } from '@js/core/renderer';
55
import $ from '@js/core/renderer';
66
import type { DeferredObj } from '@js/core/utils/deferred';
77
import { Deferred } from '@js/core/utils/deferred';
8-
import { extend } from '@js/core/utils/extend';
98
import { isDefined } from '@js/core/utils/type';
9+
import type { ItemInfo, NativeEventInfo } from '@js/events';
10+
import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base';
1011
import DataExpressionMixin from '@js/ui/editor/ui.data_expression';
1112
import type { Properties } from '@js/ui/radio_group';
1213
import type { OptionChanged } from '@ts/core/widget/types';
13-
import type { EditorProperties, UnresolvedEvents } from '@ts/ui/editor/editor';
14+
import type { EditorProperties, UnresolvedEvents, ValueChangedEvent } from '@ts/ui/editor/editor';
1415
import Editor from '@ts/ui/editor/editor';
1516

1617
import RadioCollection from './m_radio_collection';
@@ -28,21 +29,18 @@ interface RadioGroupProperties extends Properties,
2829
class RadioGroup extends Editor<RadioGroupProperties> {
2930
private _radios?: RadioCollection;
3031

31-
private _areRadiosCreated!: DeferredObj<unknown>;
32+
private _areRadiosCreated!: DeferredObj<void>;
3233

3334
private _$submitElement!: dxElementWrapper;
3435

35-
// eslint-disable-next-line class-methods-use-this
3636
_dataSourceOptions(): { paginate: boolean } {
3737
return { paginate: false };
3838
}
3939

40-
// eslint-disable-next-line class-methods-use-this
4140
protected _activeStateUnit(): string {
4241
return `.${RADIO_BUTTON_CLASS}`;
4342
}
4443

45-
// eslint-disable-next-line class-methods-use-this
4644
protected _feedbackHideTimeout(): number {
4745
return RADIO_FEEDBACK_HIDE_TIMEOUT;
4846
}
@@ -63,32 +61,38 @@ class RadioGroup extends Editor<RadioGroupProperties> {
6361
}]);
6462
}
6563

66-
// @ts-expect-error
64+
// @ts-expect-error widget.ts _fireContentReadyAction should accept an optional `force` parameter
6765
_fireContentReadyAction(force: boolean): void {
68-
force && super._fireContentReadyAction();
66+
if (!force) {
67+
return;
68+
}
69+
70+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
71+
super._fireContentReadyAction();
6972
}
7073

71-
_focusTarget() {
74+
_focusTarget(): dxElementWrapper {
7275
return this.$element();
7376
}
7477

75-
_getAriaTarget() {
78+
_getAriaTarget(): dxElementWrapper {
7679
return this.$element();
7780
}
7881

79-
_getDefaultOptions() {
80-
const defaultOptions = super._getDefaultOptions();
81-
82-
// @ts-expect-error
83-
return extend(defaultOptions, extend(DataExpressionMixin._dataExpressionDefaultOptions(), {
82+
_getDefaultOptions(): RadioGroupProperties {
83+
return {
84+
...super._getDefaultOptions(),
85+
// @ts-expect-error DataExpressionMixin should expose _dataExpressionDefaultOptions as a
86+
// typed static method
87+
...DataExpressionMixin._dataExpressionDefaultOptions(),
8488
hoverStateEnabled: true,
8589
activeStateEnabled: true,
8690
layout: 'vertical',
87-
}));
91+
} as RadioGroupProperties;
8892
}
8993

90-
_getItemValue(item) {
91-
// @ts-expect-error
94+
_getItemValue(item: ItemLike): unknown {
95+
// @ts-expect-error valueGetter is injected by DataExpressionMixin
9296
return this._valueGetter ? this._valueGetter(item) : item.text;
9397
}
9498

@@ -99,7 +103,7 @@ class RadioGroup extends Editor<RadioGroupProperties> {
99103
_init(): void {
100104
super._init();
101105

102-
// @ts-expect-error
106+
// @ts-expect-error _initDataExpressions is injected by DataExpressionMixin
103107
this._initDataExpressions();
104108
}
105109

@@ -112,28 +116,29 @@ class RadioGroup extends Editor<RadioGroupProperties> {
112116
super._initMarkup();
113117
}
114118

115-
_itemClickHandler({ itemElement, event, itemData }): void {
116-
// @ts-expect-error
117-
if (this.itemElements().is(itemElement)) {
119+
_itemClickHandler({ itemElement, event, itemData }:
120+
NativeEventInfo<RadioCollection, MouseEvent | PointerEvent> & ItemInfo): void {
121+
if (this.itemElements()?.is($(itemElement))) {
122+
const { value } = this.option();
118123
const newValue = this._getItemValue(itemData);
119124

120-
if (newValue !== this.option('value')) {
121-
this._saveValueChangeEvent(event);
125+
if (newValue !== value) {
126+
this._saveValueChangeEvent(event as unknown as ValueChangedEvent);
122127
this.option('value', newValue);
123128
}
124129
}
125130
}
126131

127-
_getSelectedItemKeys(value) {
128-
// @ts-expect-error
129-
const isNullSelectable = this.option('valueExpr') !== 'this';
130-
const shouldSelectValue = isNullSelectable && value === null || isDefined(value);
132+
_getSelectedItemKeys(value: unknown): unknown[] {
133+
const { valueExpr } = this.option();
134+
const isNullSelectable = valueExpr !== 'this';
135+
const shouldSelectValue = (isNullSelectable && value === null) || isDefined(value);
131136

132137
return shouldSelectValue ? [value] : [];
133138
}
134139

135-
_setSelection(currentValue): void {
136-
// @ts-expect-error
140+
_setSelection(currentValue: unknown): void {
141+
// @ts-expect-error _unwrappedValue is injected by DataExpressionMixin
137142
const value = this._unwrappedValue(currentValue);
138143
this._setCollectionWidgetOption('selectedItemKeys', this._getSelectedItemKeys(value));
139144
}
@@ -147,7 +152,7 @@ class RadioGroup extends Editor<RadioGroupProperties> {
147152

148153
_optionChanged(args: OptionChanged<RadioGroupProperties>): void {
149154
const { name, value } = args;
150-
// @ts-expect-error
155+
// @ts-expect-error _dataExpressionOptionChanged is injected by DataExpressionMixin
151156
this._dataExpressionOptionChanged(args);
152157

153158
switch (name) {
@@ -164,7 +169,7 @@ class RadioGroup extends Editor<RadioGroupProperties> {
164169
this._setCollectionWidgetOption(name, value);
165170
break;
166171
case 'valueExpr':
167-
// @ts-expect-error
172+
// @ts-expect-error _getCollectionKeyExpr is injected by DataExpressionMixin
168173
this._setCollectionWidgetOption('keyExpr', this._getCollectionKeyExpr());
169174
break;
170175
case 'value':
@@ -173,7 +178,7 @@ class RadioGroup extends Editor<RadioGroupProperties> {
173178
super._optionChanged(args);
174179
break;
175180
case 'items':
176-
this._setSelection(this.option('value'));
181+
this._setSelection(this.option().value);
177182
break;
178183
case 'itemTemplate':
179184
case 'displayExpr':
@@ -215,21 +220,20 @@ class RadioGroup extends Editor<RadioGroupProperties> {
215220
onInitialized: ({ component }) => {
216221
this._radios = component;
217222
},
218-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
219-
onContentReady: (e) => {
223+
onContentReady: () => {
220224
this._fireContentReadyAction(true);
221225
},
222-
// @ts-expect-error
223226
onItemClick: this._itemClickHandler.bind(this),
224227
displayExpr,
225228
accessKey,
226-
// @ts-expect-error
229+
// @ts-expect-error _dataSource is injected by DataExpressionMixin
227230
dataSource: this._dataSource,
228231
focusStateEnabled,
229232
itemTemplate,
230-
// @ts-expect-error
233+
// @ts-expect-error _getCollectionKeyExpr is injected by DataExpressionMixin
231234
keyExpr: this._getCollectionKeyExpr(),
232235
noDataText: '',
236+
// @ts-expect-error scrollingEnabled is absent from CollectionWidgetProperties
233237
scrollingEnabled: false,
234238
selectByClick: false,
235239
selectionMode: 'single',
@@ -249,35 +253,33 @@ class RadioGroup extends Editor<RadioGroupProperties> {
249253

250254
_setOptionsByReference(): void {
251255
super._setOptionsByReference();
252-
extend(this._optionsByReference, { value: true });
256+
this._optionsByReference = { ...this._optionsByReference, value: true };
253257
}
254258

255259
_setSubmitValue(value?: unknown): void {
256-
value = value ?? this.option('value');
257-
// @ts-expect-error
258-
const submitValue = this.option('valueExpr') === 'this'
259-
// @ts-expect-error
260-
? this._displayGetter(value)
261-
: value;
260+
const { valueExpr, value: optionValue } = this.option();
261+
const resolvedValue = value ?? optionValue;
262262

263-
this._$submitElement.val(submitValue);
264-
}
263+
const submitValue = valueExpr === 'this'
264+
// @ts-expect-error _displayGetter is injected by DataExpressionMixin
265+
? this._displayGetter(resolvedValue)
266+
: resolvedValue;
265267

266-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
267-
_setCollectionWidgetOption(name: string, value: unknown): void {
268-
// @ts-expect-error
268+
this._$submitElement.val(submitValue as string | number | undefined);
269+
}
269270

270-
this._areRadiosCreated.done(this._setWidgetOption.bind(this, '_radios', arguments));
271+
_setCollectionWidgetOption(...args: [string, unknown]): void {
272+
// @ts-expect-error widget._setWidgetOption args should be typed as ArrayLike<unknown>
273+
this._areRadiosCreated.done(this._setWidgetOption.bind(this, '_radios', args));
271274
}
272275

273276
_updateItemsSize(): void {
274-
const { layout } = this.option();
277+
const { layout, items } = this.option();
275278

276279
if (layout === 'horizontal') {
277280
this.itemElements()?.css('height', 'auto');
278281
} else {
279-
// @ts-expect-error
280-
const itemsCount = this.option('items').length;
282+
const itemsCount = (items ?? []).length;
281283

282284
this.itemElements()?.css('height', `${100 / itemsCount}%`);
283285
}
@@ -291,7 +293,7 @@ class RadioGroup extends Editor<RadioGroupProperties> {
291293
return this._radios?._itemElements();
292294
}
293295
}
294-
// @ts-expect-error
296+
// @ts-expect-error Widget base class should define a typed static include() method
295297
RadioGroup.include(DataExpressionMixin);
296298

297299
registerComponent('dxRadioGroup', RadioGroup);

0 commit comments

Comments
 (0)