Skip to content

Commit 0f29746

Browse files
r-farkhutdinovRuslan Farkhutdinov
andauthored
Switch: Improve TS types, remove ts-ignore and warnings (DevExpress#30474)
Co-authored-by: Ruslan Farkhutdinov <[email protected]>
1 parent 998323e commit 0f29746

File tree

3 files changed

+118
-95
lines changed

3 files changed

+118
-95
lines changed

packages/devextreme/js/__internal/events/gesture/m_swipeable.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
import eventsEngine from '@js/common/core/events/core/events_engine';
2+
import type {
3+
SwipeEndEvent,
4+
SwipeStartEvent,
5+
SwipeUpdateEvent,
6+
} from '@js/common/core/events/swipe';
27
import {
38
end as swipeEventEnd,
49
start as swipeEventStart,
@@ -29,9 +34,9 @@ export interface SwipeableProperties extends DOMComponentProperties {
2934
immediateTimeout?: number;
3035
direction?: string;
3136
itemSizeFunc?: (() => number) | null;
32-
onStart?: ((e) => void) | null;
33-
onUpdated?: ((e) => void) | null;
34-
onEnd?: ((e) => void) | null;
37+
onStart?: ((e: SwipeStartEvent) => void) | null;
38+
onUpdated?: ((e: SwipeUpdateEvent) => void) | null;
39+
onEnd?: ((e: SwipeEndEvent) => void) | null;
3540
onCancel?: ((e) => void) | null;
3641
disabled?: boolean;
3742
}

packages/devextreme/js/__internal/events/m_swipe.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ const SWIPE_START_EVENT = 'dxswipestart';
77
const SWIPE_EVENT = 'dxswipe';
88
const SWIPE_END_EVENT = 'dxswipeend';
99

10+
export interface SwipeEvent<T> {
11+
event: Event & T;
12+
}
13+
14+
export type SwipeStartEvent = SwipeEvent<{ maxLeftOffset: number; maxRightOffset: number }>;
15+
export type SwipeUpdateEvent = SwipeEvent<{ offset: number }>;
16+
export type SwipeEndEvent = SwipeEvent<{ targetOffset: number }>;
17+
1018
const HorizontalStrategy = {
1119
defaultItemSizeFunc() {
1220
return getWidth(this.getElement());

packages/devextreme/js/__internal/ui/m_switch.ts

Lines changed: 102 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ import type { DeferredObj } from '@js/core/utils/deferred';
1414
import { Deferred } from '@js/core/utils/deferred';
1515
import { getBoundingRect } from '@js/core/utils/position';
1616
import { getOuterWidth } from '@js/core/utils/size';
17+
import type { NativeEventInfo } from '@js/events';
1718
import type { Properties } from '@js/ui/switch';
1819
import type { OptionChanged } from '@ts/core/widget/types';
20+
import type { SwipeEndEvent, SwipeStartEvent, SwipeUpdateEvent } from '@ts/events/m_swipe';
1921
import Editor from '@ts/ui/editor/editor';
2022

2123
const SWITCH_CLASS = 'dx-switch';
@@ -55,22 +57,25 @@ class Switch extends Editor<Properties> {
5557
_supportedKeys(): Record<string, (e: KeyboardEvent, options?: Record<string, unknown>) => void> {
5658
const { rtlEnabled } = this.option();
5759

58-
const click = function (e) {
60+
const click = (e: Event): void => {
5961
e.preventDefault();
60-
this._clickAction({ event: e });
62+
this._clickAction?.({ event: e });
6163
};
62-
const move = function (value, e) {
64+
65+
const move = (value: boolean, e: KeyboardEvent): void => {
6366
e.preventDefault();
6467
e.stopPropagation();
68+
// @ts-expect-error ValueChangedEvent should be compatible with KeyboardEvent
6569
this._saveValueChangeEvent(e);
6670
this._animateValue(value);
6771
};
72+
6873
return {
6974
...super._supportedKeys(),
7075
space: click,
7176
enter: click,
72-
leftArrow: move.bind(this, !!rtlEnabled),
73-
rightArrow: move.bind(this, !rtlEnabled),
77+
leftArrow: (e): void => { move(Boolean(rtlEnabled), e); },
78+
rightArrow: (e): void => { move(!rtlEnabled, e); },
7479
};
7580
}
7681

@@ -132,24 +137,25 @@ class Switch extends Editor<Properties> {
132137
this._renderValue();
133138
}
134139

135-
_getInnerOffset(value, offset): string {
140+
_getInnerOffset(value: boolean, offset: number): string {
136141
const ratio = (offset - this._offsetDirection() * Number(!value)) / 2;
137142
return `${100 * ratio}%`;
138143
}
139144

140-
_getHandleOffset(value, offset): string {
141-
if (this.option('rtlEnabled')) {
142-
value = !value;
143-
}
145+
_getHandleOffset(value: boolean, offset: number): string {
146+
const { rtlEnabled } = this.option();
147+
148+
const valueWithRtl = rtlEnabled ? !value : value;
144149

145-
if (value) {
150+
if (valueWithRtl) {
146151
const calcValue = -100 + 100 * -offset;
147152
return `${calcValue}%`;
148153
}
154+
149155
return `${100 * -offset}%`;
150156
}
151157

152-
_renderSwitchInner() {
158+
_renderSwitchInner(): void {
153159
this._$switchInner = $('<div>')
154160
.addClass(SWITCH_INNER_CLASS)
155161
.appendTo(this._$switchContainer);
@@ -159,7 +165,7 @@ class Switch extends Editor<Properties> {
159165
.appendTo(this._$switchInner);
160166
}
161167

162-
_renderLabels() {
168+
_renderLabels(): void {
163169
this._$labelOn = $('<div>')
164170
.addClass(SWITCH_ON_CLASS)
165171
.prependTo(this._$switchInner);
@@ -171,7 +177,7 @@ class Switch extends Editor<Properties> {
171177
this._setLabelsText();
172178
}
173179

174-
_renderContainers() {
180+
_renderContainers(): void {
175181
this._$switchContainer = $('<div>')
176182
.addClass(SWITCH_CONTAINER_CLASS);
177183

@@ -180,19 +186,20 @@ class Switch extends Editor<Properties> {
180186
.append(this._$switchContainer);
181187
}
182188

183-
_renderSwipeable() {
189+
_renderSwipeable(): void {
184190
this._createComponent(this.$element(), Swipeable, {
185191
elastic: false,
186192
immediate: true,
187-
onStart: this._swipeStartHandler.bind(this),
188-
onUpdated: this._swipeUpdateHandler.bind(this),
189-
onEnd: this._swipeEndHandler.bind(this),
190-
itemSizeFunc: this._getItemSizeFunc.bind(this),
193+
onStart: (e): void => this._swipeStartHandler(e),
194+
onUpdated: (e): void => this._swipeUpdateHandler(e),
195+
onEnd: (e): void => this._swipeEndHandler(e),
196+
itemSizeFunc: () => this._getItemSizeFunc(),
191197
});
192198
}
193199

194200
_getItemSizeFunc(): number {
195-
return getOuterWidth(this._$switchContainer, true) - getBoundingRect(this._$handle.get(0)).width;
201+
return getOuterWidth(this._$switchContainer, true)
202+
- getBoundingRect(this._$handle.get(0)).width;
196203
}
197204

198205
_renderSubmitElement(): void {
@@ -206,10 +213,11 @@ class Switch extends Editor<Properties> {
206213
}
207214

208215
_offsetDirection(): number {
209-
return this.option('rtlEnabled') ? -1 : 1;
216+
const { rtlEnabled } = this.option();
217+
return rtlEnabled ? -1 : 1;
210218
}
211219

212-
_renderPosition(state, swipeOffset): void {
220+
_renderPosition(state: boolean, swipeOffset: number): void {
213221
const innerOffset = this._getInnerOffset(state, swipeOffset);
214222
const handleOffset = this._getHandleOffset(state, swipeOffset);
215223

@@ -218,39 +226,42 @@ class Switch extends Editor<Properties> {
218226
}
219227

220228
_validateValue(): void {
221-
const check = this.option('value');
229+
const { value: check } = this.option();
222230
if (typeof check !== 'boolean') {
223231
this._options.silent('value', !!check);
224232
}
225233
}
226234

227235
_renderClick(): void {
228-
// @ts-expect-error ts-error
229-
const eventName = addNamespace(clickEventName, this.NAME);
236+
const eventName = addNamespace(clickEventName, this.NAME ?? '');
230237
const $element = this.$element();
231238
this._clickAction = this._createAction(this._clickHandler.bind(this));
232239

233240
eventsEngine.off($element, eventName);
234-
eventsEngine.on($element, eventName, (e) => {
241+
eventsEngine.on($element, eventName, (e: Event): void => {
235242
this._clickAction?.({ event: e });
236243
});
237244
}
238245

239-
_clickHandler(args): void {
240-
const e = args.event;
246+
_clickHandler(args: NativeEventInfo<Switch, MouseEvent | PointerEvent>): void {
247+
const { event } = args;
241248

242-
this._saveValueChangeEvent(e);
249+
// @ts-expect-error ValueChangedEvent should be compatible with KeyboardEvent
250+
this._saveValueChangeEvent(event);
243251

244252
if (this._animating || this._swiping) {
245253
return;
246254
}
247255

248-
this._animateValue(!this.option('value'));
256+
const { value } = this.option();
257+
258+
this._animateValue(!value);
249259
}
250260

251-
_animateValue(value): void {
252-
const startValue = this.option('value');
253-
const endValue = value;
261+
_animateValue(newValue: boolean): void {
262+
const { value } = this.option();
263+
const startValue = Boolean(value);
264+
const endValue = newValue;
254265

255266
if (startValue === endValue) {
256267
return;
@@ -263,113 +274,112 @@ class Switch extends Editor<Properties> {
263274
const fromHandleOffset = this._getHandleOffset(startValue, 0);
264275
const toHandleOffset = this._getHandleOffset(endValue, 0);
265276

266-
const that = this;
267-
const fromInnerConfig = {};
268-
const toInnerConfig = {};
269-
const fromHandleConfig = {};
270-
const toHandlerConfig = {};
271-
// @ts-expect-error ts-error
272-
fromInnerConfig.transform = ` translateX(${fromInnerOffset})`;
273-
// @ts-expect-error ts-error
274-
toInnerConfig.transform = ` translateX(${toInnerOffset})`;
275-
// @ts-expect-error ts-error
276-
fromHandleConfig.transform = ` translateX(${fromHandleOffset})`;
277-
// @ts-expect-error ts-error
278-
toHandlerConfig.transform = ` translateX(${toHandleOffset})`;
277+
const fromInnerConfig = { transform: ` translateX(${fromInnerOffset})` };
278+
const toInnerConfig = { transform: ` translateX(${toInnerOffset})` };
279+
const fromHandleConfig = { transform: ` translateX(${fromHandleOffset})` };
280+
const toHandlerConfig = { transform: ` translateX(${toHandleOffset})` };
279281

280282
this.$element().toggleClass(SWITCH_ON_VALUE_CLASS, endValue);
281-
// @ts-expect-error ts-error
282-
fx.animate(this._$handle, {
283+
284+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
285+
fx.animate(this._$handle.get(0), {
286+
// @ts-expect-error AnimationState type should be extended
283287
from: fromHandleConfig,
288+
// @ts-expect-error AnimationState type should be extended
284289
to: toHandlerConfig,
285290
duration: SWITCH_ANIMATION_DURATION,
286291
});
287-
// @ts-expect-error ts-error
288-
fx.animate(this._$switchInner, {
292+
293+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
294+
fx.animate(this._$switchInner.get(0), {
295+
// @ts-expect-error AnimationState type should be extended
289296
from: fromInnerConfig,
297+
// @ts-expect-error AnimationState type should be extended
290298
to: toInnerConfig,
291299
duration: SWITCH_ANIMATION_DURATION,
292-
complete() {
293-
that._animating = false;
294-
that.option('value', endValue);
300+
complete: () => {
301+
this._animating = false;
302+
this.option({ value: endValue });
295303
},
296304
});
297305
}
298306

299-
_swipeStartHandler(e): void {
300-
const state = this.option('value');
301-
const rtlEnabled = this.option('rtlEnabled');
307+
_swipeStartHandler(e: SwipeStartEvent): void {
308+
const { value: state, rtlEnabled, activeStateEnabled } = this.option();
302309
const maxOffOffset = rtlEnabled ? 0 : 1;
303310
const maxOnOffset = rtlEnabled ? 1 : 0;
304311

305312
e.event.maxLeftOffset = state ? maxOffOffset : maxOnOffset;
306313
e.event.maxRightOffset = state ? maxOnOffset : maxOffOffset;
314+
307315
this._swiping = true;
308316

309317
this._feedbackDeferred = Deferred();
310318
lock(this._feedbackDeferred);
311-
const { activeStateEnabled } = this.option();
312-
// @ts-expect-error ts-error
313-
this._toggleActiveState(this.$element(), activeStateEnabled);
319+
320+
this._toggleActiveState(this.$element(), Boolean(activeStateEnabled));
314321
}
315322

316-
_swipeUpdateHandler(e): void {
317-
this._renderPosition(this.option('value'), e.event.offset);
323+
_swipeUpdateHandler(e: SwipeUpdateEvent): void {
324+
const { value } = this.option();
325+
this._renderPosition(Boolean(value), e.event.offset);
318326
}
319327

320-
_swipeEndHandler(e): void {
321-
const that = this;
328+
_swipeEndHandler(e: SwipeEndEvent): void {
329+
const { value } = this.option();
330+
322331
const offsetDirection = this._offsetDirection();
323-
const toInnerConfig = {};
324-
const toHandleConfig = {};
325-
326-
const innerOffset = this._getInnerOffset(that.option('value'), e.event.targetOffset);
327-
const handleOffset = this._getHandleOffset(that.option('value'), e.event.targetOffset);
328-
// @ts-expect-error
329-
toInnerConfig.transform = ` translateX(${innerOffset})`;
330-
// @ts-expect-error
331-
toHandleConfig.transform = ` translateX(${handleOffset})`;
332-
// @ts-expect-error ts-error
333-
fx.animate(this._$handle, {
332+
333+
const innerOffset = this._getInnerOffset(Boolean(value), e.event.targetOffset);
334+
const handleOffset = this._getHandleOffset(Boolean(value), e.event.targetOffset);
335+
336+
const toInnerConfig = { transform: ` translateX(${innerOffset})` };
337+
const toHandleConfig = { transform: ` translateX(${handleOffset})` };
338+
339+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
340+
fx.animate(this._$handle.get(0), {
341+
// @ts-expect-error AnimationState type should be extended
334342
to: toHandleConfig,
335343
duration: SWITCH_ANIMATION_DURATION,
336344
});
337-
// @ts-expect-error ts-error
338-
fx.animate(this._$switchInner, {
345+
346+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
347+
fx.animate(this._$switchInner.get(0), {
348+
// @ts-expect-error AnimationState type should be extended
339349
to: toInnerConfig,
340350
duration: SWITCH_ANIMATION_DURATION,
341-
complete() {
342-
that._swiping = false;
343-
// @ts-expect-error ts-error
344-
const pos = that.option('value') + offsetDirection * e.event.targetOffset;
345-
that._saveValueChangeEvent(e.event);
346-
that.option('value', Boolean(pos));
347-
that._feedbackDeferred?.resolve();
348-
that._toggleActiveState(that.$element(), false);
351+
complete: () => {
352+
this._swiping = false;
353+
const pos = Number(value) + offsetDirection * e.event.targetOffset;
354+
// @ts-expect-error ValueChangedEvent should be compatible with KeyboardEvent
355+
this._saveValueChangeEvent(e.event);
356+
this.option({ value: Boolean(pos) });
357+
this._feedbackDeferred?.resolve();
358+
this._toggleActiveState(this.$element(), false);
349359
},
350360
});
351361
}
352362

353363
_renderValue(): void {
354364
this._validateValue();
355365

356-
const { value } = this.option();
357-
this._renderPosition(value, 0);
366+
const { value, switchedOnText, switchedOffText } = this.option();
367+
368+
this._renderPosition(Boolean(value), 0);
358369

359370
this.$element().toggleClass(SWITCH_ON_VALUE_CLASS, value);
360-
// @ts-expect-error ts-error
361-
this._getSubmitElement().val(value);
371+
372+
this._getSubmitElement().val(String(value ?? ''));
362373
this.setAria({
363374
checked: value,
364-
label: value ? this.option('switchedOnText') : this.option('switchedOffText'),
375+
label: value ? switchedOnText : switchedOffText,
365376
});
366377
}
367378

368379
_setLabelsText(): void {
369-
const { switchedOnText, switchedOffText } = this.option();
370-
// @ts-expect-error ts-error
380+
const { switchedOnText = '', switchedOffText = '' } = this.option();
381+
371382
this._$labelOn?.text(switchedOnText);
372-
// @ts-expect-error ts-error
373383
this._$labelOff?.text(switchedOffText);
374384
}
375385

0 commit comments

Comments
 (0)