Skip to content

Commit 2eacc8d

Browse files
committed
WIP Fix typescript-eslint issues
1 parent 0bf5546 commit 2eacc8d

13 files changed

+46
-23
lines changed

eslint.config.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,25 +134,31 @@ const config = tsEslint.config([
134134
{
135135
files: ['**/*.ts', '**/*.tsx'],
136136

137-
extends: tsEslint.configs.recommended,
137+
extends: tsEslint.configs.recommendedTypeChecked,
138138

139139
languageOptions: {
140140
parserOptions: {
141141
projectService: {
142142
allowDefaultProject: ['eslint.config.ts', 'knip.ts'],
143+
// Needed because `import * as ... from` instead of `import ... from` doesn't work in this file
144+
// for some imports.
145+
defaultProject: 'tsconfig.eslint.json',
143146
},
144147
},
145148
},
146149

147150
rules: {
148151
'@typescript-eslint/no-namespace': 'off',
149152
'@typescript-eslint/no-shadow': 'error',
153+
// Too many false positives
154+
'@typescript-eslint/no-unnecessary-condition': 'off',
150155
'@typescript-eslint/no-unused-vars': [
151156
'error',
152157
{
153158
caughtErrorsIgnorePattern: '^_',
154159
},
155160
],
161+
'@typescript-eslint/restrict-template-expressions': 'off',
156162
},
157163
},
158164
// must be the last config in the array

node_package/src/ClientSideRenderer.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const REACT_ON_RAILS_STORE_ATTRIBUTE = 'data-js-react-on-rails-store';
1616

1717
function delegateToRenderer(
1818
componentObj: RegisteredComponent,
19-
props: Record<string, string>,
19+
props: Record<string, unknown>,
2020
railsContext: RailsContext,
2121
domNodeId: string,
2222
trace: boolean,
@@ -81,7 +81,7 @@ class ComponentRenderer {
8181
// This must match lib/react_on_rails/helper.rb
8282
const name = el.getAttribute('data-component-name') || '';
8383
const { domNodeId } = this;
84-
const props = el.textContent !== null ? JSON.parse(el.textContent) : {};
84+
const props = el.textContent !== null ? (JSON.parse(el.textContent) as Record<string, unknown>) : {};
8585
const trace = el.getAttribute('data-trace') === 'true';
8686

8787
try {
@@ -183,15 +183,18 @@ class StoreRenderer {
183183
}
184184

185185
const name = storeDataElement.getAttribute(REACT_ON_RAILS_STORE_ATTRIBUTE) || '';
186-
const props = storeDataElement.textContent !== null ? JSON.parse(storeDataElement.textContent) : {};
186+
const props =
187+
storeDataElement.textContent !== null
188+
? (JSON.parse(storeDataElement.textContent) as Record<string, unknown>)
189+
: {};
187190
this.hydratePromise = this.hydrate(context, railsContext, name, props);
188191
}
189192

190193
private async hydrate(
191194
context: Context,
192195
railsContext: RailsContext,
193196
name: string,
194-
props: Record<string, string>,
197+
props: Record<string, unknown>,
195198
) {
196199
const storeGenerator = await context.ReactOnRails.getOrWaitForStoreGenerator(name);
197200
if (this.state === 'unmounted') {

node_package/src/ComponentRegistry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type RegisteredComponent, type ReactComponentOrRenderFunction, type RenderFunction } from './types';
1+
import { type RegisteredComponent, type ReactComponentOrRenderFunction } from './types';
22
import isRenderFunction from './isRenderFunction';
33
import CallbackRegistry from './CallbackRegistry';
44

@@ -20,7 +20,7 @@ export default {
2020
}
2121

2222
const renderFunction = isRenderFunction(component);
23-
const isRenderer = renderFunction && (component as RenderFunction).length === 3;
23+
const isRenderer = renderFunction && component.length === 3;
2424

2525
componentRegistry.set(name, {
2626
name,

node_package/src/ReactOnRails.client.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@ if (ctx === undefined) {
2525
}
2626

2727
if (ctx.ReactOnRails !== undefined) {
28+
/* eslint-disable @typescript-eslint/no-base-to-string -- Window and Global both have useful toString() */
2829
throw new Error(`
2930
The ReactOnRails value exists in the ${ctx} scope, it may not be safe to overwrite it.
30-
31+
3132
This could be caused by setting Webpack's optimization.runtimeChunk to "true" or "multiple," rather than "single." Check your Webpack configuration.
32-
33+
3334
Read more at https://github.com/shakacode/react_on_rails/issues/1558.
3435
`);
36+
/* eslint-enable @typescript-eslint/no-base-to-string */
3537
}
3638

3739
const DEFAULT_OPTIONS = {

node_package/src/buildConsoleReplay.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export function consoleReplay(
3737
val = 'undefined';
3838
}
3939
} catch (e) {
40+
// eslint-disable-next-line @typescript-eslint/no-base-to-string -- if we here, JSON.stringify didn't work
4041
val = `${(e as Error).message}: ${arg}`;
4142
}
4243

node_package/src/context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export function getContextAndRailsContext(): { context: Context | null; railsCon
5353
}
5454

5555
try {
56-
currentRailsContext = JSON.parse(el.textContent);
56+
currentRailsContext = JSON.parse(el.textContent) as RailsContext;
5757
} catch (e) {
5858
console.error('Error parsing Rails context:', e);
5959
return { context: null, railsContext: null };

node_package/src/isRenderFunction.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export default function isRenderFunction(
1212
component: ReactComponentOrRenderFunction,
1313
): component is RenderFunction {
1414
// No for es5 or es6 React Component
15+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1516
if ((component as RenderFunction).prototype?.isReactComponent) {
1617
return false;
1718
}

node_package/src/loadReactClientManifest.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import * as path from 'path';
22
import * as fs from 'fs/promises';
33

4-
const loadedReactClientManifests = new Map<string, Record<string, unknown>>();
4+
type ClientManifest = Record<string, unknown>;
5+
const loadedReactClientManifests = new Map<string, ClientManifest>();
56

67
export default async function loadReactClientManifest(reactClientManifestFileName: string) {
78
// React client manifest is uploaded to node renderer as an asset.
@@ -11,7 +12,7 @@ export default async function loadReactClientManifest(reactClientManifestFileNam
1112
if (!loadedReactClientManifests.has(manifestPath)) {
1213
// TODO: convert to async
1314
try {
14-
const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
15+
const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8')) as ClientManifest;
1516
loadedReactClientManifests.set(manifestPath, manifest);
1617
} catch (error) {
1718
throw new Error(`Failed to load React client manifest from ${manifestPath}: ${error}`);

node_package/src/reactHydrateOrRender.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,18 @@ type HydrateOrRenderType = (domNode: Element, reactElement: ReactElement) => Ren
77

88
// TODO: once React dependency is updated to >= 18, we can remove this and just
99
// import ReactDOM from 'react-dom/client';
10-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
11-
let reactDomClient: any;
10+
let reactDomClient: typeof import('react-dom/client');
1211
if (supportsRootApi) {
1312
// This will never throw an exception, but it's the way to tell Webpack the dependency is optional
1413
// https://github.com/webpack/webpack/issues/339#issuecomment-47739112
1514
// Unfortunately, it only converts the error to a warning.
1615
try {
1716
// eslint-disable-next-line global-require,@typescript-eslint/no-require-imports
18-
reactDomClient = require('react-dom/client');
17+
reactDomClient = require('react-dom/client') as typeof import('react-dom/client');
1918
} catch (_e) {
2019
// We should never get here, but if we do, we'll just use the default ReactDOM
2120
// and live with the warning.
22-
reactDomClient = ReactDOM;
21+
reactDomClient = ReactDOM as unknown as typeof import('react-dom/client');
2322
}
2423
}
2524

node_package/src/streamServerRenderedReactComponent.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const stringToStream = (str: string): Readable => {
1717
return stream;
1818
};
1919

20-
type BufferdEvent = {
20+
type BufferedEvent = {
2121
event: 'data' | 'error' | 'end';
2222
data: unknown;
2323
};
@@ -38,7 +38,7 @@ type BufferdEvent = {
3838
* - emitError: A function to manually emit errors into the stream
3939
*/
4040
const bufferStream = (stream: Readable) => {
41-
const bufferedEvents: BufferdEvent[] = [];
41+
const bufferedEvents: BufferedEvent[] = [];
4242
let startedReading = false;
4343

4444
const listeners = (['data', 'error', 'end'] as const).map((event) => {
@@ -58,7 +58,7 @@ const bufferStream = (stream: Readable) => {
5858

5959
// Remove initial listeners
6060
listeners.forEach(({ event, listener }) => stream.off(event, listener));
61-
const handleEvent = ({ event, data }: BufferdEvent) => {
61+
const handleEvent = ({ event, data }: BufferedEvent) => {
6262
if (event === 'data') {
6363
this.push(data);
6464
} else if (event === 'error') {
@@ -96,7 +96,8 @@ export const transformRenderStreamChunksToResultObject = (renderState: StreamRen
9696

9797
const transformStream = new PassThrough({
9898
transform(chunk, _, callback) {
99-
const htmlChunk = chunk.toString();
99+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
100+
const htmlChunk = chunk.toString() as string;
100101
const consoleReplayScript = buildConsoleReplay(consoleHistory, previouslyReplayedConsoleMessages);
101102
previouslyReplayedConsoleMessages = consoleHistory?.length || 0;
102103

node_package/src/transformRSCStreamAndReplayConsoleLogs.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
export default function transformRSCStreamAndReplayConsoleLogs(stream: ReadableStream) {
1+
import { RenderResult } from './types';
2+
3+
export default function transformRSCStreamAndReplayConsoleLogs(stream: ReadableStream<Uint8Array>) {
24
return new ReadableStream({
35
async start(controller) {
46
const reader = stream.getReader();
@@ -16,7 +18,7 @@ export default function transformRSCStreamAndReplayConsoleLogs(stream: ReadableS
1618
.filter((line) => line.trim() !== '')
1719
.map((line) => {
1820
try {
19-
return JSON.parse(line);
21+
return JSON.parse(line) as RenderResult;
2022
} catch (error) {
2123
console.error('Error parsing JSON:', line, error);
2224
throw error;
@@ -25,7 +27,7 @@ export default function transformRSCStreamAndReplayConsoleLogs(stream: ReadableS
2527

2628
for (const jsonChunk of jsonChunks) {
2729
const { html, consoleReplayScript = '' } = jsonChunk;
28-
controller.enqueue(encoder.encode(html));
30+
controller.enqueue(encoder.encode(html ?? ''));
2931

3032
const replayConsoleCode = consoleReplayScript
3133
.trim()

node_package/src/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ export interface ReactOnRails {
171171
/** @deprecated Use registerStoreGenerators instead */
172172
registerStore(stores: Record<string, StoreGenerator>): void;
173173
registerStoreGenerators(storeGenerators: Record<string, StoreGenerator>): void;
174+
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
174175
getStore(name: string, throwIfMissing?: boolean): Store | undefined;
175176
getOrWaitForStore(name: string): Promise<Store>;
176177
getOrWaitForStoreGenerator(name: string): Promise<StoreGenerator>;

tsconfig.eslint.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"allowSyntheticDefaultImports": true
5+
}
6+
}

0 commit comments

Comments
 (0)