Skip to content

Core(utils): type 6 m_ files ahead of the rename, part 2 (26_1) - #35505

Draft
EugeniyKiyashko wants to merge 33 commits into
DevExpress:26_1from
EugeniyKiyashko:typescript/core/utils_typing_5039_part2_26_1
Draft

EugeniyKiyashko wants to merge 33 commits into
DevExpress:26_1from
EugeniyKiyashko:typescript/core/utils_typing_5039_part2_26_1

Conversation

@EugeniyKiyashko

Copy link
Copy Markdown
Contributor

No description provided.

@EugeniyKiyashko EugeniyKiyashko self-assigned this Oct 6, 2026
@EugeniyKiyashko
EugeniyKiyashko force-pushed the typescript/core/utils_typing_5039_part2_26_1 branch 3 times, most recently from 9233d84 to d55c391 Compare October 7, 2026 09:12
The signatures stay as loose as the callers use them today (any values,
any results), so no caller changes its types. extend takes a rest
parameter instead of arguments; the loops step with += 1.

ui.gantt.cache loses the ts-expect-error that expected the missing
third argument of extendFromObject.
m_error: the helpers are declared before the object that holds them, the
parameters are no longer reassigned, and Error keeps being a function
expression because callers use it with new.

m_date_serialization: the helpers are declared before their callers,
String#match becomes RegExp#exec (no g or y flags), the month of an ISO
string is computed instead of decremented in place, and the results of
the public functions stay any for the callers.
m_selection_filter: the constructor function gets a typed this and its
helpers are declared before the methods that use them.

m_shadow_dom: the hash function keeps its bitwise operations under
reasoned disables; the index loops over DOM collections become for-of.
The tests pass on the code before the typing.
The overloads type the callbacks of arrays, readonly arrays, nullable arrays and
dictionaries. An empty array literal (never[]) and an untyped {} keep untyped callbacks,
and a loose overload stays last for the callers that pass any.

The callers get type-only fixes: 26 ts-expect-error directives where a declared type does
not match the use, a cast of the scrollbar direction, an annotation of the popup item and
a removed redundant cast. The emitted code of all 17 files is identical.
The overloads return the type of the target merged with the types of the sources, for the
shallow form, the deep form (true first) and the forms where a missing target (false,
null, undefined) makes extend create a new object. An any source gives an any result,
and a loose overload stays last for the callers that spread their arguments.

The callers get type-only fixes: 55 ts-expect-error directives where the merged type is
not the type that the caller declares or uses, two annotations in the pivot grid, an
optional third parameter of foreachNodes and one removed redundant cast; two directives
that the new types made unnecessary are removed. The emitted code of all 33 files is
identical.
deserializeDate returns a date or the unparsed input (never a number), serializeDate
returns the input, a number, a string or null, and getDateSerializationFormat returns a
string, null or undefined.

The callers get type-only fixes: five as string and as Date casts like the ones that the
other callers of these functions already use, and six ts-expect-error directives where the
declared type of the caller is narrower than what the function can return. The emitted
code of all 7 files is identical.
Error is callable and constructible (new errors.Error is used in m_data, filter_builder
and the grid), takes the id and the details and returns a DxError; log takes the id and
the details. The four ts-expect-error directives that waited for Error to be declared as a
constructor are removed, and the unneeded no-unsafe-return disable in m_error goes too.

The callers get type-only fixes: a cast of the id in data/errors, three directives where
a caller spreads untyped arguments or passes an optional code, and seven directives in
the Jest tests that mock Error with an empty object. The emitted code is identical.
The filter builder was typed in DevExpress#35477 after the hub typing was cut: its action config is
the merged object that the action options do not accept. Only a directive is added, the
emitted code is unchanged.
The typed each, map, reverseEach, extend, date functions and errors left 97
ts-expect-error directives in the callers. This commit types the callers, and
19 directives are left, each says what is not typed.

What replaced the directives:
- annotations of the merged objects (the scrollable options, the pop-up
  toolbar item, the screen items of the responsive box, the position result,
  the root directory info, the dragging panels, the actions of the filter
  builder, the date serializer of the date box)
- ProcessedColumn and ProcessedLookup for the columns that have
  calculateCellValue and index, used in the columns controller, the adaptivity
  and the validating
- casts to a named type where the merged object is completed later or the
  generic type is chosen by the caller (the label options, the selection
  options, the speed dial options, the cloned options, the widget instance)
- real signatures: ActionConfig takes the ActionEvent of Action, extend
  skips a void source, the trailing parameters of the filter custom operations
  are optional like in the public type, the default export option of the
  diagram toolbar has an optional file name, getBoundingRect is public in the
  views that the dragging code calls
- 17 eslint-disable comments that the typed callers made stale are removed

Only ui/chat/messagelist.ts changes the emitted code: Number() instead of the
subtraction of two dates (the same result for a Date, a number, a string, null
and undefined). The emitted code of the 63 other changed files is identical.
…iles

Eight errors in six files that this branch did not touch, found by the full
eslint run after the rebase onto the newer main (the typed extend and each
make a cast unnecessary, and the typed string makes match a prefer-regexp-exec
error):
- 5 casts of the result of extend to the type that it already has are removed
  (devices, card_view, grid_core widget, toolbar utils, work_space x2)
- animation/fx: String#match with a regexp without the g flag becomes
  RegExp#exec, the same result (the only change of the emitted code here)
…d of ignoring them

The context menu controller calls _getRows and getContextMenuItems of the grid
views. The views declared _getRows as protected, getContextMenuItems was
private in two extenders and not declared in the base, so the two calls had a
ts-expect-error each. Now _getRows is public in the five view classes (the
change parameter of the rows view is optional like in the base class),
ColumnsView declares the optional getContextMenuItems and the two extenders
make it public. The directive of adaptivity_rows_view that expected the
missing declaration is removed too.

The scrollable strategy declared the action handler with a
Record<string, unknown> argument while the component returns a handler that
takes unknown, so the call that merges the action args needed a directive.
The declaration follows the component now.

Three directives of the hub typing and one older directive are removed, 16 are
left. The emitted code is identical.
Copilot review: normalizeLoadResult does not make extra an object. An array
without a second argument gives extra: undefined and any other value of the
second argument is passed through, so the cast to Record<string, unknown> and
the interface that it needed made the contract unsound. utils.ts is back to
the base version, and the one place where the declared LoadResult type is
ahead of the data (an object extra only exists after _processStoreLoadResult
has normalized it) has a ts-expect-error that says so.

The emitted code is identical.
The sortable that is typed in main now passes extend({}, animationConfig, { to })
to animate. The typed extend models a merge as an intersection, so the new to
is intersected with the string | AnimationState of the public animation config
and the result does not fit AnimateConfig. The new to replaces the old one at
run time, so the merged object is an AnimateConfig, and the call says so.

The emitted code is identical.
Copilot review: MergedSource used NonNullable<T>, so extend({}, source) with
source: { value: string } | undefined typed result.value as string, but an
undefined source is skipped at run time and value is absent. A source whose
type contains null, undefined or void now adds Partial<NonNullable<T>>; a
source that is always present keeps its properties required. No caller of
extend needs a change (tsc is clean), and two type tests in m_extend.test.ts
pin both cases (they are checked by tsc, ts-jest does not type-check).

The emitted code is identical.
… any fallback

extend types its result by the order of the sources (a later source wins, an
undefined value is skipped, a deep merge recurses into plain objects).
each, map and reverseEach are typed overloads with a typed implementation,
the date functions have overloads by the input and the format.
The callers are typed instead of cast: satisfies for literal options, the
internal option types where the runtime passes null or a renderer, honest
callback parameters (renderer items are elements, node arrays hold null).
…error, shadow dom

SelectionFilterCreator is an ES6 class generic by the item and the key, so its
callers (selection strategy, TagBox, the tests) use its type instead of a copy.
m_error types its arguments as a tuple, the data errors narrow by a DxError
guard, m_shadow_dom handles a missing style sheet and narrows nodes by guards.
…suppressing them

- renderer: an internal attr(attributes) overload, 20 directives removed
- Diagram panels, TreeView, Gantt: option types for the options they take
  and for the null defaults
- pivot grid, live update, OData: guards instead of directives and casts
- scheduler: the workspace config is built without an invalid cast
- grid view: the never-registered errorView is dropped from the view list
- menu: _getPlainItems flattens the items of the third and deeper levels
…the jQuery 1/2 context

$submenu.context exists only in jQuery 1.x and 2.x, so with the renderer and
jQuery 3+ the submenus of the sibling items stayed shown on click.
FilterBuilder types moved to types.ts: the internal operations keep a nullable
filter expression and the value-text customizeText; the items get their id on
creation. Sortable passes the element type to getPublicElement.
@EugeniyKiyashko
EugeniyKiyashko force-pushed the typescript/core/utils_typing_5039_part2_26_1 branch from 660fe02 to 2e035fe Compare October 7, 2026 14:44
…replaces

- DOMComponent, Widget, DiagramFloatingPanel: the default options are a spread;
  the undefined entries were skipped by extend and are dropped
- grids: a hasCellValueCalculator guard instead of ProcessedColumn casts,
  an explicit index check in adaptivity
- SpeedDial: the action options are a partial patch, onClick can be null
- satisfies DataType[], parseFloat(String(width))
…pointment date reads

- findBestMatches is generic by the filter and the item, no cast of the item
- Form: the runtime info returns the widget union, getEditor and getButton narrow it
  by instanceof (getButton is typed by the Button wrapper it returns)
- Scheduler: the date field of the form and of the data accessor is read in one place
OptionAction<THandler> derives the arguments of an action from the handler of its
option without the EventInfo fields that the action adds itself; the panel events
are EventInfo<panel> plus their own fields. The visibility actions no longer pass
the component, the action sets it.
@github-actions github-actions Bot added the .d.ts label Oct 7, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant