Skip to content

Modernize toolchain: React 17, TypeScript 4.9, Node 16, and strict type fixes#320

Open
asuh wants to merge 3 commits intoetesync:masterfrom
asuh:modernize-etesync
Open

Modernize toolchain: React 17, TypeScript 4.9, Node 16, and strict type fixes#320
asuh wants to merge 3 commits intoetesync:masterfrom
asuh:modernize-etesync

Conversation

@asuh
Copy link
Copy Markdown
Contributor

@asuh asuh commented May 3, 2026

Summary

Upgrades the core toolchain incrementally to more modern, supported versions and resolves all TypeScript strict type-checking errors introduced by the upgrade. Set up future upgrades to React 18 and 19. Bumps the project version to 0.7.0.

Changes

1. Upgrade React 17, TypeScript 4.9, and Node 16 baseline (f865a22)

  • Add .nvmrc pinned to Node 16
  • Upgrade react and react-dom from ^16.13.1 to ^17.0.2
  • Upgrade typescript from ~3.9.7 to ~4.9.5
  • Upgrade @types/node to ^16.0.0, @types/react to ^17.0.0, @types/react-dom to ^17.0.0
  • Add resolutions for @types/react and @types/react-dom to prevent duplicate type versions causing JSX component type conflicts
  • Fix type errors from stricter TS 4.9 checks:
    • Cast Link as any in MUI IconButton component prop (Collection.tsx, CollectionList.tsx)
    • Replace endDate getter override in TaskType with Object.defineProperty in constructor (pim-types.ts)
    • Wrap ExternalLink with React.forwardRef for MUI ButtonBase ref forwarding (ExternalLink.tsx)

2. Resolve TypeScript strict type-checking errors (f8519a4)

  • Remove deprecated suppressImplicitAnyIndexErrors from tsconfig.json, add ignoreDeprecations: "6.0"
  • Add explicit Record<string, any> type annotations to object literals used with dynamic string keys across 17 files
  • Cast dynamic state property access in class components (ContactEdit, GroupEdit)
  • Cast zones.zones/zones.aliases for bracket-notation access in pim-types.ts
  • Replace theme.palette.primary[500] with theme.palette.primary.main (Material-UI v4 best practice)

3. Bump to version 0.7.0 (95b5dbb)

Motivation

The previous toolchain (React 16, TypeScript 3.9, no Node version pinning) was outdated and made it difficult to adopt newer libraries or take advantage of improved type safety. These changes bring the project to a stable, maintained baseline while keeping the upgrade incremental and low-risk (no breaking API changes in React 16→17).

Testing

  • Project compiles cleanly with tsc (no type errors)
  • Existing test suite passes
  • No runtime behavioral changes expected (React 17 is a "stepping stone" release with no new developer-facing features)

asuh added 3 commits May 3, 2026 11:22
- Add .nvmrc pinned to Node 16
- Upgrade react and react-dom from ^16.13.1 to ^17.0.2
- Upgrade typescript from ~3.9.7 to ~4.9.5
- Upgrade @types/node from ^11.9.3 to ^16.0.0
- Upgrade @types/react from ^16.9.0 to ^17.0.0
- Upgrade @types/react-dom from ^16.9.0 to ^17.0.0
- Add resolutions for @types/react and @types/react-dom to prevent
  duplicate versions causing JSX component type conflicts

Fix type errors introduced by stricter TypeScript 4.9 checks:

- Cast Link as any in IconButton component prop (Collection.tsx,
  CollectionList.tsx) to work around MUI 4 typing limitations
- Replace endDate getter override in TaskType with Object.defineProperty
  in constructor (pim-types.ts) since TS 4.9 disallows overriding a
  class property with an accessor
- Wrap ExternalLink with React.forwardRef so MUI ButtonBase can attach
  refs when used as a component prop (ExternalLink.tsx)
- tsconfig.json: Remove deprecated suppressImplicitAnyIndexErrors option,
  add ignoreDeprecations: '6.0' for other legacy options

- Add explicit Record<string, any> type annotations to object literals
  used with dynamic string keys:
  - CollectionEdit: colTypes
  - CollectionImport, CollectionList: collectionMap
  - ContactEdit, GroupEdit: collectionGroups, originalGroups, groups
  - Contacts/Toolbar, Tasks/Toolbar: transitionStyles (Record<string, React.CSSProperties>)
  - Debug: wantedEntries (Record<string, boolean>)
  - persist-state-history: stateCache
  - routes: RouteResolver.routes and constructor param

- Cast dynamic state property access to (prevState as any)[name] in
  ContactEdit and GroupEdit (addValueType, removeValueType,
  handleValueTypeChange methods)

- Cast zones.zones and zones.aliases to Record<string, any> in
  pim-types.ts timezoneLoadFromName for bracket notation access

- Cast actions to Record<string, any> in store/reducers.ts for
  dynamic property access in fetchActions loop

- Cast updatedOptions to Record<string, any> in RRule.tsx for
  dynamic key iteration and deletion; cast bysetpos and bymonthday
  to number[] for array element access

- Add Record<string, any> constraint to insertSorted generic in
  helpers.tsx; cast self.state[part] for dynamic property access
  in handleInputChange

- Replace theme.palette.primary[500] with theme.palette.primary.main
  in SearchableAddressBook and TaskList (Material-UI v4 best practice)
@asuh
Copy link
Copy Markdown
Contributor Author

asuh commented May 3, 2026

@tasn Hey, I hope this is helpful to incrementally migrate this project to a more modern stack.

After this PR merges to master, there are multiple directions you could go:

  1. Vite - The most common Create React App replacement. Uses esbuild for dev and Rollup for production builds.
  2. Parcel - It's a zero-config bundler but less popular. Uses SWC under the hood.
  3. Rsbuild - Rspack-based (Rust webpack-compatible bundler). It's newer but gaining traction, measureably faster than Webpack
  4. Webpack - Keeping parity with other etesync projects using Webpack. Shows its age in setup and speed but mature ecosystem.

I'll let you decide what makes sense.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant