diff --git a/.github/actions/reanimated-typescript-compatibility-check/action.yml b/.github/actions/reanimated-typescript-compatibility-check/action.yml index 2be8f9357a2d..c03d1bd759e1 100644 --- a/.github/actions/reanimated-typescript-compatibility-check/action.yml +++ b/.github/actions/reanimated-typescript-compatibility-check/action.yml @@ -19,10 +19,15 @@ runs: shell: bash run: yarn up react-native@${{ inputs.react-native-version }} - - name: Check source types + - name: Check native source types shell: bash working-directory: packages/react-native-reanimated - run: yarn type:check:src + run: yarn type:check:src:native + + - name: Check web source types + shell: bash + working-directory: packages/react-native-reanimated + run: yarn type:check:src:web - name: Check plugin types shell: bash diff --git a/.lintstagedrc-common.js b/.lintstagedrc-common.js index 4d8668128b05..27f15743c5f9 100644 --- a/.lintstagedrc-common.js +++ b/.lintstagedrc-common.js @@ -1,4 +1,4 @@ -/** @type {import('lint-staged').Config} */ +/** @type {import('lint-staged').Configuration} */ module.exports = { '*.(js|jsx|ts|tsx)': [ 'yarn eslint --flag v10_config_lookup_from_file', diff --git a/apps/common-app/.lintstagedrc.js b/apps/common-app/.lintstagedrc.js index c42170990fd3..bad117e1fc4f 100644 --- a/apps/common-app/.lintstagedrc.js +++ b/apps/common-app/.lintstagedrc.js @@ -1,7 +1,8 @@ -/** @type {import('lint-staged').Config} */ +/* eslint-disable @typescript-eslint/no-require-imports */ +/** @type {import('lint-staged').Configuration} */ const commonConfig = require('../../.lintstagedrc-common.js'); -/** @type {import('lint-staged').Config} */ +/** @type {import('lint-staged').Configuration} */ module.exports = { ...commonConfig, }; diff --git a/apps/common-app/eslint.config.mjs b/apps/common-app/eslint.config.mjs index 8ec44f2fde28..d5a9fafd370a 100644 --- a/apps/common-app/eslint.config.mjs +++ b/apps/common-app/eslint.config.mjs @@ -1,17 +1,18 @@ +import { fixupPluginRules } from '@eslint/compat'; import jsEslint from '@eslint/js'; -import tsEslint from 'typescript-eslint'; -import perfectionist from 'eslint-plugin-perfectionist'; -import reactNative from 'eslint-plugin-react-native'; -import react from 'eslint-plugin-react'; -import globals from 'globals'; import importPlugin from 'eslint-plugin-import'; +import noRelativeImportPaths from 'eslint-plugin-no-relative-import-paths'; +import perfectionist from 'eslint-plugin-perfectionist'; import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; +import react from 'eslint-plugin-react'; +// eslint-disable-next-line import/default import reactHooks from 'eslint-plugin-react-hooks'; -import noRelativeImportPaths from 'eslint-plugin-no-relative-import-paths'; +// @ts-expect-error eslint-plugin-react-native has no types. +import reactNative from 'eslint-plugin-react-native'; import simpleImportSort from 'eslint-plugin-simple-import-sort'; import unusedImports from 'eslint-plugin-unused-imports'; -import { fixupPluginRules } from '@eslint/compat'; -import { globalIgnores } from 'eslint/config'; +import globals from 'globals'; +import tsEslint from 'typescript-eslint'; /** @type {import('typescript-eslint').ConfigWithExtends[]} */ export default tsEslint.config( @@ -21,14 +22,30 @@ export default tsEslint.config( eslintPluginPrettierRecommended, { languageOptions: { + parserOptions: { + parser: tsEslint.parser, + project: [ + './tsconfig.json', + './tsconfig.web.json', + './../../tsconfig.json', + ], + tsconfigRootDir: import.meta.dirname, + }, + }, + }, + { + languageOptions: { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment globals: { React: true, + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access ...reactNative.environments['react-native']['react-native'], ...globals.node, }, }, plugins: { 'no-relative-import-paths': noRelativeImportPaths, + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument 'react-native': fixupPluginRules(reactNative), 'simple-import-sort': simpleImportSort, 'unused-imports': unusedImports, @@ -267,7 +284,6 @@ export default tsEslint.config( 'import/resolver': { typescript: { alwaysTryTypes: true, - project: './tsconfig.json', }, }, react: { @@ -276,15 +292,7 @@ export default tsEslint.config( }, }, { - files: ['**/*.ts', '**/*.tsx'], extends: [tsEslint.configs.recommendedTypeChecked], - languageOptions: { - parserOptions: { - parser: tsEslint.parser, - project: './tsconfig.json', - tsconfigRootDir: import.meta.dirname, - }, - }, rules: { '@typescript-eslint/array-type': ['error', { default: 'generic' }], '@typescript-eslint/consistent-type-exports': 'error', @@ -328,6 +336,5 @@ export default tsEslint.config( '@typescript-eslint/no-unsafe-member-access': 'error', 'no-underscore-dangle': 'error', }, - }, - globalIgnores(['**/eslint.config.mjs']) + } ); diff --git a/apps/common-app/package.json b/apps/common-app/package.json index 8b2eba4dfcdc..a5e5eb9462db 100644 --- a/apps/common-app/package.json +++ b/apps/common-app/package.json @@ -7,7 +7,9 @@ "lint": "eslint . --flag v10_config_lookup_from_file", "format": "prettier --write --list-different .", "circular-dependency-check": "yarn madge --extensions js,jsx,ts,tsx --circular src", - "type:check": "tsc --noEmit", + "type:check": "yarn type:check:native && yarn type:check:web", + "type:check:native": "tsc --noEmit", + "type:check:web": "tsc --noEmit --project tsconfig.web.json", "type:check:strict": "tsc --noEmit --customConditions react-native-strict-api" }, "peerDependencies": { diff --git a/apps/common-app/scripts/dependencies.js b/apps/common-app/scripts/dependencies.js index 9c1bcfbc4b90..085372e43675 100644 --- a/apps/common-app/scripts/dependencies.js +++ b/apps/common-app/scripts/dependencies.js @@ -1,3 +1,7 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-require-imports */ const path = require('path'); /** diff --git a/apps/common-app/src/apps/css/components/cards/ExpandableCard.tsx b/apps/common-app/src/apps/css/components/cards/ExpandableCard.tsx index 15da741434e0..7675dc51311a 100644 --- a/apps/common-app/src/apps/css/components/cards/ExpandableCard.tsx +++ b/apps/common-app/src/apps/css/components/cards/ExpandableCard.tsx @@ -50,6 +50,9 @@ export default function ExpandableCard({ style={[styles.overlay, { height: overlayHeight }]}> + {/* TODO: Fix me */} + {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} + {/* @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 */} ({ () => ( + {/* TODO: Fix me */} + {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} + {/* @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 */} + {/* TODO: Fix me */} + {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} + {/* @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 */} @@ -131,6 +137,9 @@ type FlameProps = { function Flame({ height, width }: FlameProps) { return ( + {/* TODO: Fix me */} + {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} + {/* @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 */} diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Circle.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Circle.tsx index 782aa72e4b1c..fcd2247ef23c 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Circle.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Circle.tsx @@ -1,4 +1,7 @@ import Animated, { type CSSAnimationKeyframes } from 'react-native-reanimated'; +// TODO: Fix me +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 import { Circle, type CircleProps, Svg } from 'react-native-svg'; import { ExamplesScreen } from '@/apps/css/components'; diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Ellipse.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Ellipse.tsx index 4052ac8acc1a..44379f3aba98 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Ellipse.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Ellipse.tsx @@ -1,4 +1,7 @@ import Animated, { type CSSAnimationKeyframes } from 'react-native-reanimated'; +// TODO: Fix me +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 import { Ellipse, type EllipseProps, Svg } from 'react-native-svg'; import { ExamplesScreen } from '@/apps/css/components'; diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Line.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Line.tsx index 134d6bc3f9ae..ecdfbdf7f157 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Line.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Line.tsx @@ -1,4 +1,7 @@ import Animated, { type CSSAnimationKeyframes } from 'react-native-reanimated'; +// TODO: Fix me +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 import { Line, type LineProps, Svg } from 'react-native-svg'; import { ExamplesScreen } from '@/apps/css/components'; diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Rect.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Rect.tsx index 6d6af2416102..fcd8a168227b 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Rect.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Rect.tsx @@ -1,4 +1,7 @@ import Animated, { type CSSAnimationKeyframes } from 'react-native-reanimated'; +// TODO: Fix me +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 import { Rect, type RectProps, Svg } from 'react-native-svg'; import { ExamplesScreen } from '@/apps/css/components'; diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/common/FillAndColor.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/common/FillAndColor.tsx index e43bc25d0062..e26d3ddd42c7 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/common/FillAndColor.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/common/FillAndColor.tsx @@ -1,13 +1,16 @@ +import type { JSX } from 'react'; import Animated, { type CSSAnimationKeyframes, type CSSAnimationProperties, } from 'react-native-reanimated'; +// TODO: Fix me +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 import type { CircleProps, PolygonProps } from 'react-native-svg'; import { Circle, Polygon, Svg } from 'react-native-svg'; import { ExamplesScreen } from '@/apps/css/components'; import type { AnyRecord } from '@/types'; -import type { JSX } from 'react'; const AnimatedCircle = Animated.createAnimatedComponent(Circle); const AnimatedPolygon = Animated.createAnimatedComponent(Polygon); diff --git a/apps/common-app/src/apps/css/examples/animations/screens/realWorldExamples/Emojis.tsx b/apps/common-app/src/apps/css/examples/animations/screens/realWorldExamples/Emojis.tsx index 5285489709b1..5a54f94f64b0 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/realWorldExamples/Emojis.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/realWorldExamples/Emojis.tsx @@ -283,8 +283,14 @@ function YayEmoji() { + {/* TODO: Fix me */} + {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} + {/* @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 */} @@ -628,8 +634,14 @@ function AngryEmoji() { + {/* TODO: Fix me */} + {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} + {/* @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 */} diff --git a/apps/common-app/src/apps/css/examples/animations/screens/realWorldExamples/RocketInSpace.tsx b/apps/common-app/src/apps/css/examples/animations/screens/realWorldExamples/RocketInSpace.tsx index f8c047d8e3c0..733c19ade129 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/realWorldExamples/RocketInSpace.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/realWorldExamples/RocketInSpace.tsx @@ -67,7 +67,13 @@ export default function RocketInSpace() { + {/* TODO: Fix me */} + {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} + {/* @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 */} + {/* TODO: Fix me */} + {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} + {/* @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 */} @@ -186,6 +192,9 @@ type FlameProps = { function Flame({ height, width }: FlameProps) { return ( + {/* TODO: Fix me */} + {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} + {/* @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 */} diff --git a/apps/common-app/src/apps/css/examples/transitions/screens/realWorldExamples/FlexGallery.tsx b/apps/common-app/src/apps/css/examples/transitions/screens/realWorldExamples/FlexGallery.tsx index 862dfe0f4041..c0a4103dac38 100644 --- a/apps/common-app/src/apps/css/examples/transitions/screens/realWorldExamples/FlexGallery.tsx +++ b/apps/common-app/src/apps/css/examples/transitions/screens/realWorldExamples/FlexGallery.tsx @@ -103,6 +103,9 @@ function GalleryCard({ const gradient = useMemo( () => ( + {/* TODO: Fix me */} + {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} + {/* @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 */} diff --git a/apps/common-app/src/apps/css/navigation/BottomTabBar.tsx b/apps/common-app/src/apps/css/navigation/BottomTabBar.tsx index 9e1657360504..c5282408939b 100644 --- a/apps/common-app/src/apps/css/navigation/BottomTabBar.tsx +++ b/apps/common-app/src/apps/css/navigation/BottomTabBar.tsx @@ -59,6 +59,9 @@ export default function BottomTabBar({ const gradient = useMemo( () => ( + {/* TODO: Fix me */} + {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} + {/* @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 */} diff --git a/apps/common-app/src/apps/reanimated/eslint.config.mjs b/apps/common-app/src/apps/reanimated/eslint.config.mjs index caf06d385599..f3ed2a584d32 100644 --- a/apps/common-app/src/apps/reanimated/eslint.config.mjs +++ b/apps/common-app/src/apps/reanimated/eslint.config.mjs @@ -1,10 +1,12 @@ import jsEslint from '@eslint/js'; import tsEslint from 'typescript-eslint'; +// @ts-expect-error No types for this package. import reactNative from 'eslint-plugin-react-native'; import { fixupPluginRules } from '@eslint/compat'; import { globalIgnores } from 'eslint/config'; import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; import reanimated from 'eslint-plugin-reanimated'; +// @ts-expect-error No types for this package. import noInlineStyles from 'eslint-plugin-no-inline-styles'; import react from 'eslint-plugin-react'; import reactHooks from 'eslint-plugin-react-hooks'; @@ -15,6 +17,14 @@ export default tsEslint.config( jsEslint.configs.recommended, react.configs.flat.recommended, eslintPluginPrettierRecommended, + { + languageOptions: { + parserOptions: { + project: ['../../../tsconfig.json', './../../../tsconfig.web.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, + }, { languageOptions: { globals: { @@ -58,7 +68,6 @@ export default tsEslint.config( 'import/resolver': { typescript: { alwaysTryTypes: true, - project: '../../../tsconfig.json', }, }, react: { @@ -69,12 +78,6 @@ export default tsEslint.config( { files: ['**/*.ts', '**/*.tsx'], extends: [tsEslint.configs.recommendedTypeChecked], - languageOptions: { - parserOptions: { - project: '../../../tsconfig.json', - tsconfigRootDir: import.meta.dirname, - }, - }, rules: { '@typescript-eslint/no-unused-vars': 'warn', '@typescript-eslint/no-var-requires': 'error', diff --git a/apps/common-app/src/apps/reanimated/examples/PlanetsExample.tsx b/apps/common-app/src/apps/reanimated/examples/PlanetsExample.tsx index 0296becc5e9a..2b188fcb7afb 100644 --- a/apps/common-app/src/apps/reanimated/examples/PlanetsExample.tsx +++ b/apps/common-app/src/apps/reanimated/examples/PlanetsExample.tsx @@ -99,6 +99,8 @@ function BottomSun() { export default function PlanetsExample() { return ( + {/* TODO: Fix me */} + {/* @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 */} { return ( selectClick(item)} selectedTests={selectedTests} /> diff --git a/apps/common-app/src/apps/reanimated/examples/SwipeableListExample.tsx b/apps/common-app/src/apps/reanimated/examples/SwipeableListExample.tsx index ea4d4e9aa2c3..ad522d307772 100644 --- a/apps/common-app/src/apps/reanimated/examples/SwipeableListExample.tsx +++ b/apps/common-app/src/apps/reanimated/examples/SwipeableListExample.tsx @@ -69,7 +69,11 @@ export default function SwipeableListExample() { } + // TODO: Fix me + // @ts-ignore RNGH types for web FlatList are broken. keyExtractor={(item) => item.id} /> diff --git a/apps/common-app/tsconfig.json b/apps/common-app/tsconfig.json index a66d35b738aa..8b800e86b2d3 100644 --- a/apps/common-app/tsconfig.json +++ b/apps/common-app/tsconfig.json @@ -1,10 +1,5 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - }, - "include": ["src", "index.ts"] + // To explore web types in your IDE you can temporarily change this line to: + // "extends": "./tsconfig.web.json" + "extends": "./tsconfig.native.json" } diff --git a/apps/common-app/tsconfig.native.json b/apps/common-app/tsconfig.native.json new file mode 100644 index 000000000000..6d48198deafa --- /dev/null +++ b/apps/common-app/tsconfig.native.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src", "index.ts"], + "exclude": ["**/*.web.ts", "**/*.web.tsx"] +} diff --git a/apps/common-app/tsconfig.web.json b/apps/common-app/tsconfig.web.json new file mode 100644 index 000000000000..51b3063389bb --- /dev/null +++ b/apps/common-app/tsconfig.web.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.native.json", + "compilerOptions": { + "moduleSuffixes": [".web", ""] + }, + "exclude": [ + "**/*.native.ts", + "**/*.native.tsx", + "**/*.ios.ts", + "**/*.ios.tsx", + "**/*.android.ts", + "**/*.android.tsx" + ] +} diff --git a/apps/fabric-example/eslint.config.mjs b/apps/fabric-example/eslint.config.mjs new file mode 100644 index 000000000000..3ca98f0a5fb0 --- /dev/null +++ b/apps/fabric-example/eslint.config.mjs @@ -0,0 +1,20 @@ +import tsEslint from 'typescript-eslint'; + +import eslintConfig from '../../eslint.config.mjs'; + +/** + * @type {( + * | import('typescript-eslint').ConfigWithExtends + * | import('eslint').Linter.Config + * )[]} + */ +const config = tsEslint.config(...eslintConfig, { + languageOptions: { + parserOptions: { + project: ['./tsconfig.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, +}); + +export default config; diff --git a/apps/fabric-example/package.json b/apps/fabric-example/package.json index 516923586a31..513f7e197aeb 100644 --- a/apps/fabric-example/package.json +++ b/apps/fabric-example/package.json @@ -8,6 +8,7 @@ "ios": "react-native run-ios", "start": "react-native start", "format": "prettier --write --list-different .", + "lint": "eslint . --max-warnings 0", "type:check": "tsc --noEmit" }, "dependencies": { @@ -17,6 +18,7 @@ }, "devDependencies": { "@types/react": "19.2.2", + "eslint": "9.37.0", "prettier": "3.6.2", "typescript": "5.8.3" }, diff --git a/apps/fabric-example/tsconfig.json b/apps/fabric-example/tsconfig.json index 3f5061a50a7b..cb0deb8be680 100644 --- a/apps/fabric-example/tsconfig.json +++ b/apps/fabric-example/tsconfig.json @@ -6,12 +6,6 @@ "@/*": ["../common-app/src/*"] } }, - "exclude": [ - "**/node_modules", - "**/Pods", - "metro.config.js", - "android", - "ios", - ".bundle" - ] + "include": ["."], + "exclude": ["android", "ios", ".bundle", "vendor", "assets"] } diff --git a/apps/macos-example/eslint.config.mjs b/apps/macos-example/eslint.config.mjs new file mode 100644 index 000000000000..3ca98f0a5fb0 --- /dev/null +++ b/apps/macos-example/eslint.config.mjs @@ -0,0 +1,20 @@ +import tsEslint from 'typescript-eslint'; + +import eslintConfig from '../../eslint.config.mjs'; + +/** + * @type {( + * | import('typescript-eslint').ConfigWithExtends + * | import('eslint').Linter.Config + * )[]} + */ +const config = tsEslint.config(...eslintConfig, { + languageOptions: { + parserOptions: { + project: ['./tsconfig.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, +}); + +export default config; diff --git a/apps/macos-example/package.json b/apps/macos-example/package.json index f23d6674bf4d..aa7cc18c49d1 100644 --- a/apps/macos-example/package.json +++ b/apps/macos-example/package.json @@ -6,6 +6,7 @@ "macos": "react-native run-macos", "build": "cd macos && bundle install && bundle exec pod update", "format": "prettier --write --list-different .", + "lint": "eslint . --max-warnings 0", "start": "react-native start", "type:check": "tsc --noEmit" }, diff --git a/apps/macos-example/tsconfig.json b/apps/macos-example/tsconfig.json index d44a1f66875c..d54a7d5e909d 100644 --- a/apps/macos-example/tsconfig.json +++ b/apps/macos-example/tsconfig.json @@ -6,5 +6,7 @@ "@/*": ["../common-app/src/*"] // "react": ["./node_modules/@types/react"] } - } + }, + "include": ["."], + "exclude": [".bundle", "macos", "vendor"] } diff --git a/apps/next-example/eslint.config.mjs b/apps/next-example/eslint.config.mjs new file mode 100644 index 000000000000..c974d88ee31a --- /dev/null +++ b/apps/next-example/eslint.config.mjs @@ -0,0 +1,21 @@ +import tsEslint from 'typescript-eslint'; + +import eslintConfig from '../../eslint.config.mjs'; + +/** + * @type {( + * | import('typescript-eslint').ConfigWithExtends + * | import('eslint').Linter.Config + * )[]} + */ +const config = tsEslint.config(...eslintConfig, { + languageOptions: { + parserOptions: { + project: ['./tsconfig.json'], + tsconfigRootDir: import.meta.dirname, + ecmaFeatures: { jsx: true }, + }, + }, +}); + +export default config; diff --git a/apps/next-example/next.config.js b/apps/next-example/next.config.js index cc3250efba83..db87578ca55f 100644 --- a/apps/next-example/next.config.js +++ b/apps/next-example/next.config.js @@ -9,12 +9,16 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({ // this can be used to obtain a more readable bundle for debugging const disableMinification = process.env.DISABLE_MINIFICATION === '1'; +/** @type {import('next').NextConfig} */ module.exports = withPlugins([withBundleAnalyzer, withExpo], { // transpilePackages is a Next.js +13.1 feature. // older versions can use next-transpile-modules eslint: { ignoreDuringBuilds: true, }, + typescript: { + ignoreBuildErrors: true, + }, transpilePackages: ['react-native-reanimated', 'react-native', 'expo'], webpack(config) { if (disableMinification) { diff --git a/apps/next-example/tsconfig.json b/apps/next-example/tsconfig.json index 925b94fd1530..7028550153b2 100644 --- a/apps/next-example/tsconfig.json +++ b/apps/next-example/tsconfig.json @@ -5,7 +5,8 @@ "incremental": true, "isolatedModules": true, "jsx": "preserve", - "noImplicitAny": false + "noImplicitAny": false, + "moduleSuffixes": [".web", ""] }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"] + "include": ["."] } diff --git a/apps/tvos-example/eslint.config.mjs b/apps/tvos-example/eslint.config.mjs new file mode 100644 index 000000000000..3ca98f0a5fb0 --- /dev/null +++ b/apps/tvos-example/eslint.config.mjs @@ -0,0 +1,20 @@ +import tsEslint from 'typescript-eslint'; + +import eslintConfig from '../../eslint.config.mjs'; + +/** + * @type {( + * | import('typescript-eslint').ConfigWithExtends + * | import('eslint').Linter.Config + * )[]} + */ +const config = tsEslint.config(...eslintConfig, { + languageOptions: { + parserOptions: { + project: ['./tsconfig.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, +}); + +export default config; diff --git a/apps/tvos-example/tsconfig.json b/apps/tvos-example/tsconfig.json index 4082f16a5d91..7fc734344e4f 100644 --- a/apps/tvos-example/tsconfig.json +++ b/apps/tvos-example/tsconfig.json @@ -1,3 +1,5 @@ { - "extends": "../../tsconfig.json" + "extends": "../../tsconfig.json", + "include": ["."], + "exclude": [".bundle", "android", "ios", "vendor"] } diff --git a/apps/web-example/eslint.config.mjs b/apps/web-example/eslint.config.mjs new file mode 100644 index 000000000000..a504263f53b2 --- /dev/null +++ b/apps/web-example/eslint.config.mjs @@ -0,0 +1,23 @@ +import tsEslint from 'typescript-eslint'; + +import eslintConfig from '../../eslint.config.mjs'; + +/** + * @type {( + * | import('typescript-eslint').ConfigWithExtends + * | import('eslint').Linter.Config + * )[]} + */ +const config = tsEslint.config(...eslintConfig, { + languageOptions: { + parserOptions: { + project: ['./tsconfig.json'], + tsconfigRootDir: import.meta.dirname, + jsxPragma: 'React', + jsxPragmaFrag: 'React.Fragment', + ecmaFeatures: { jsx: true }, + }, + }, +}); + +export default config; diff --git a/apps/web-example/package.json b/apps/web-example/package.json index 8ad504498638..81bf2e1eb62c 100644 --- a/apps/web-example/package.json +++ b/apps/web-example/package.json @@ -9,6 +9,7 @@ "production": "yarn expo export -p web && yarn serve dist --single", "format": "prettier --write --list-different .", "build": "", + "lint": "eslint . --max-warnings 0", "type:check": "tsc --noEmit" }, "dependencies": { @@ -22,6 +23,7 @@ "devDependencies": { "@expo/metro-runtime": "6.1.2", "@types/react": "19.2.2", + "eslint": "9.37.0", "prettier": "3.6.2", "serve": "14.2.5", "typescript": "5.8.3" diff --git a/apps/web-example/tsconfig.json b/apps/web-example/tsconfig.json index 3a57bfef6269..e1c47fdb5fe4 100644 --- a/apps/web-example/tsconfig.json +++ b/apps/web-example/tsconfig.json @@ -4,9 +4,10 @@ "strict": true, "baseUrl": "../..", "paths": { - "@/*": ["./apps/common-app/src/*"], - "react-native-reanimated": ["./packages/react-native-reanimated/src"] - } + "@/*": ["./apps/common-app/src/*"] + }, + "moduleSuffixes": [".web", ""] }, - "include": ["**/*.ts", "**/*.tsx"] + "include": ["."], + "exclude": [".expo", "assets"] } diff --git a/eslint.config.mjs b/eslint.config.mjs index 0648596df40b..b240a1efb9fb 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -4,6 +4,7 @@ import { globalIgnores } from 'eslint/config'; import jsdoc from 'eslint-plugin-jsdoc'; import tsdoc from 'eslint-plugin-tsdoc'; import simpleImportSort from 'eslint-plugin-simple-import-sort'; +// @ts-expect-error No types for eslint-plugin-react-native. import reactNative from 'eslint-plugin-react-native'; import jest from 'eslint-plugin-jest'; import globals from 'globals'; @@ -11,6 +12,7 @@ import importPlugin from 'eslint-plugin-import'; import reactHooks from 'eslint-plugin-react-hooks'; import react from 'eslint-plugin-react'; import nodePlugin from 'eslint-plugin-n'; +// @ts-expect-error No types for eslint-plugin-promise. import pluginPromise from 'eslint-plugin-promise'; import eslintConfigPrettier from 'eslint-config-prettier/flat'; import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; @@ -125,8 +127,13 @@ const config = tsEslint.config( ecmaVersion: 'latest', parserOptions: { ecmaFeatures: { jsx: true }, - projectService: true, + tsconfigRootDir: import.meta.dirname, + project: ['./tsconfig.json'], }, + }, + }, + { + languageOptions: { globals: { React: true, ...reactNative.environments['react-native']['react-native'], @@ -186,6 +193,9 @@ const config = tsEslint.config( '**/ios/**', '**/android/**', '**/lib/**', + '**/.next/**', + '**/macos/**', + '**/__generatedWorklets__/**', ]) ); diff --git a/packages/eslint-plugin-reanimated/eslint.config.mjs b/packages/eslint-plugin-reanimated/eslint.config.mjs new file mode 100644 index 000000000000..f5c61f5eb28c --- /dev/null +++ b/packages/eslint-plugin-reanimated/eslint.config.mjs @@ -0,0 +1,33 @@ +import tsEslint from 'typescript-eslint'; +import simpleImportSort from 'eslint-plugin-simple-import-sort'; + +import eslintConfig from '../../eslint.config.mjs'; + +/** + * @type {( + * | import('typescript-eslint').ConfigWithExtends + * | import('eslint').Linter.Config + * )[]} + */ +const config = tsEslint.config( + ...eslintConfig, + { + languageOptions: { + parserOptions: { + project: ['./tsconfig.json', '../../tsconfig.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, + }, + { + plugins: { + 'simple-import-sort': simpleImportSort, + }, + rules: { + 'no-bitwise': 'error', + }, + ignores: [], + } +); + +export default config; diff --git a/packages/react-native-reanimated/__tests__/tsconfig.json b/packages/react-native-reanimated/__tests__/tsconfig.json index 618c6c3e97b5..9be65b6409d8 100644 --- a/packages/react-native-reanimated/__tests__/tsconfig.json +++ b/packages/react-native-reanimated/__tests__/tsconfig.json @@ -1,3 +1,5 @@ { - "extends": "../../../tsconfig.json" + "extends": "../../../tsconfig.json", + "include": ["."], + "exclude": ["__snapshots__"] } diff --git a/packages/react-native-reanimated/__typetests__/tsconfig.json b/packages/react-native-reanimated/__typetests__/tsconfig.json index 738978f5c3ab..808dfaf4fa25 100644 --- a/packages/react-native-reanimated/__typetests__/tsconfig.json +++ b/packages/react-native-reanimated/__typetests__/tsconfig.json @@ -1,4 +1,4 @@ { "extends": "../../../tsconfig.json", - "include": ["common"] + "include": ["."] } diff --git a/packages/react-native-reanimated/eslint.config.mjs b/packages/react-native-reanimated/eslint.config.mjs index 250ee61bc052..3aa74fefd9a5 100644 --- a/packages/react-native-reanimated/eslint.config.mjs +++ b/packages/react-native-reanimated/eslint.config.mjs @@ -13,6 +13,18 @@ import eslintConfig from '../../eslint.config.mjs'; const config = tsEslint.config( ...eslintConfig, { + languageOptions: { + parserOptions: { + tsconfigRootDir: import.meta.dirname, + project: [ + './tsconfig.json', + './tsconfig.web.json', + '../../tsconfig.json', + './__tests__/tsconfig.json', + './__typetests__/tsconfig.json', + ], + }, + }, files: ['**/*.ts', '**/*.tsx'], rules: { '@typescript-eslint/no-empty-function': 'error', @@ -26,11 +38,6 @@ const config = tsEslint.config( }, }, { - languageOptions: { - parserOptions: { - tsconfigRootDir: import.meta.dirname, - }, - }, plugins: { reanimated, 'simple-import-sort': simpleImportSort, diff --git a/packages/react-native-reanimated/package.json b/packages/react-native-reanimated/package.json index 93efca2c5efd..b44016228ca3 100644 --- a/packages/react-native-reanimated/package.json +++ b/packages/react-native-reanimated/package.json @@ -26,8 +26,9 @@ "format:android:cmake": "find ./android -type d \\( -name build -o -name .cxx \\) -prune -o -type f -name 'CMakeLists.txt' -print | xargs ../../scripts/format-cmake.sh", "format:common": "find Common -iname \"*.h\" -o -iname \"*.cpp\" | xargs clang-format -i", "find-unused-code:js": "knip", - "type:check": "yarn type:check:src && yarn type:check:app && yarn type:check:tests:common", - "type:check:src": "yarn tsc --noEmit", + "type:check": "yarn type:check:src:native && yarn type:check:src:web && yarn type:check:app && yarn type:check:tests:common", + "type:check:src:native": "yarn tsc --noEmit", + "type:check:src:web": "yarn tsc --noEmit --project tsconfig.web.json", "type:check:app": "yarn workspace common-app type:check", "type:check:tests:common": "../../scripts/test-ts.sh __typetests__/common", "type:check:strict": "yarn type:check:strict:src && yarn type:check:strict:app", @@ -35,7 +36,6 @@ "type:check:strict:app": "yarn workspace common-app type:check:strict", "build": "yarn workspace react-native-worklets build && bob build", "circular-dependency-check": "yarn madge --extensions js,jsx --circular lib", - "use-strict-check": "node ../../scripts/validate-use-strict.js", "prepack": "cp ../../README.md ./README.md", "postpack": "rm ./README.md" }, diff --git a/packages/react-native-reanimated/src/createAnimatedComponent/getViewInfo.ts b/packages/react-native-reanimated/src/createAnimatedComponent/getViewInfo.ts index a9f1ec95e2e4..5491100fceb0 100644 --- a/packages/react-native-reanimated/src/createAnimatedComponent/getViewInfo.ts +++ b/packages/react-native-reanimated/src/createAnimatedComponent/getViewInfo.ts @@ -1,6 +1,6 @@ 'use strict'; -import type { HostInstance } from '../platform-specific/findHostInstance'; +import type { HostInstance } from '../platform-specific/types'; export function getViewInfo(element: HostInstance): { viewName?: string; diff --git a/packages/react-native-reanimated/src/css/svg/native/configs/circle.ts b/packages/react-native-reanimated/src/css/svg/native/configs/circle.ts index 15e1449a2972..fdb1bb2c4f74 100644 --- a/packages/react-native-reanimated/src/css/svg/native/configs/circle.ts +++ b/packages/react-native-reanimated/src/css/svg/native/configs/circle.ts @@ -1,4 +1,7 @@ 'use strict'; + +// TODO: Fix me +// @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 import type { CircleProps } from 'react-native-svg'; import { processOpacity } from '../processors'; diff --git a/packages/react-native-reanimated/src/css/svg/native/configs/ellipse.ts b/packages/react-native-reanimated/src/css/svg/native/configs/ellipse.ts index 79cb8fa1fea3..d96397215234 100644 --- a/packages/react-native-reanimated/src/css/svg/native/configs/ellipse.ts +++ b/packages/react-native-reanimated/src/css/svg/native/configs/ellipse.ts @@ -1,4 +1,7 @@ 'use strict'; + +// TODO: Fix me +// @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 import type { EllipseProps } from 'react-native-svg'; import type { SvgStyleBuilderConfig } from './common'; diff --git a/packages/react-native-reanimated/src/css/svg/native/configs/line.ts b/packages/react-native-reanimated/src/css/svg/native/configs/line.ts index b123db88bc27..afa6f8ab2ea1 100644 --- a/packages/react-native-reanimated/src/css/svg/native/configs/line.ts +++ b/packages/react-native-reanimated/src/css/svg/native/configs/line.ts @@ -1,4 +1,7 @@ 'use strict'; + +// TODO: Fix me +// @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 import type { LineProps } from 'react-native-svg'; import type { SvgStyleBuilderConfig } from './common'; diff --git a/packages/react-native-reanimated/src/css/svg/native/configs/path.ts b/packages/react-native-reanimated/src/css/svg/native/configs/path.ts index 7c262f58ce8c..2d890ea231d6 100644 --- a/packages/react-native-reanimated/src/css/svg/native/configs/path.ts +++ b/packages/react-native-reanimated/src/css/svg/native/configs/path.ts @@ -1,10 +1,15 @@ 'use strict'; + +// TODO: Fix me +// @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 import type { PathProps } from 'react-native-svg'; import type { SvgStyleBuilderConfig } from './common'; import { commonSvgProps } from './common'; -// @ts-expect-error - remove when more properties are added +// TODO: Fix me +// @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 +// @ts-ignore - remove when more properties are added export const SVG_PATH_PROPERTIES_CONFIG: SvgStyleBuilderConfig = { ...commonSvgProps, // TODO - add more properties diff --git a/packages/react-native-reanimated/src/css/svg/native/configs/rect.ts b/packages/react-native-reanimated/src/css/svg/native/configs/rect.ts index 1a8c4587fe3a..657dd094945c 100644 --- a/packages/react-native-reanimated/src/css/svg/native/configs/rect.ts +++ b/packages/react-native-reanimated/src/css/svg/native/configs/rect.ts @@ -1,4 +1,7 @@ 'use strict'; + +// TODO: Fix me +// @ts-ignore RNSVG doesn't export types for web, see https://github.com/software-mansion/react-native-svg/pull/2801 import type { RectProps } from 'react-native-svg'; import type { SvgStyleBuilderConfig } from './common'; diff --git a/packages/react-native-reanimated/src/fabricUtils.ts b/packages/react-native-reanimated/src/fabricUtils.ts index 4bc2a1ac7d8e..0a52602f15d2 100644 --- a/packages/react-native-reanimated/src/fabricUtils.ts +++ b/packages/react-native-reanimated/src/fabricUtils.ts @@ -1,8 +1,9 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ 'use strict'; + import type { InternalHostInstance, ShadowNodeWrapper } from './commonTypes'; -import type { HostInstance } from './platform-specific/findHostInstance'; import { findHostInstance } from './platform-specific/findHostInstance'; +import type { HostInstance } from './platform-specific/types'; let getInternalInstanceHandleFromPublicInstance: (ref: unknown) => { stateNode: { node: unknown }; diff --git a/packages/react-native-reanimated/src/fabricUtils.web.ts b/packages/react-native-reanimated/src/fabricUtils.web.ts index 3093d6c738bd..918a884cddb4 100644 --- a/packages/react-native-reanimated/src/fabricUtils.web.ts +++ b/packages/react-native-reanimated/src/fabricUtils.web.ts @@ -1,8 +1,13 @@ 'use strict'; import { ReanimatedError } from './common'; +import type { InternalHostInstance, ShadowNodeWrapper } from './commonTypes'; +import type { HostInstance } from './platform-specific/types'; -export function getShadowNodeWrapperFromRef() { +export function getShadowNodeWrapperFromRef( + _ref: InternalHostInstance, + _hostInstance?: HostInstance +): ShadowNodeWrapper { throw new ReanimatedError( 'Trying to call `getShadowNodeWrapperFromRef` on web.' ); diff --git a/packages/react-native-reanimated/src/platform-specific/findHostInstance.ts b/packages/react-native-reanimated/src/platform-specific/findHostInstance.ts index b4ccf4a8ad77..9effd3913a54 100644 --- a/packages/react-native-reanimated/src/platform-specific/findHostInstance.ts +++ b/packages/react-native-reanimated/src/platform-specific/findHostInstance.ts @@ -4,12 +4,7 @@ import { ReanimatedError } from '../common'; import type { InternalHostInstance } from '../commonTypes'; import type { IAnimatedComponentInternalBase } from '../createAnimatedComponent/commonTypes'; - -export type HostInstance = { - __internalInstanceHandle?: Record; - __nativeTag?: number; - _viewConfig?: Record; -}; +import type { HostInstance } from './types'; function findHostInstanceFastPath(maybeNativeRef: HostInstance | undefined) { if (!maybeNativeRef) { diff --git a/packages/react-native-reanimated/src/platform-specific/findHostInstance.web.ts b/packages/react-native-reanimated/src/platform-specific/findHostInstance.web.ts index e76af0f6c485..52b1091d0aa0 100644 --- a/packages/react-native-reanimated/src/platform-specific/findHostInstance.web.ts +++ b/packages/react-native-reanimated/src/platform-specific/findHostInstance.web.ts @@ -1,4 +1,11 @@ 'use strict'; -// eslint-disable-next-line @typescript-eslint/no-empty-function -export function findHostInstance(_component: any): void {} +import type { InternalHostInstance } from '../commonTypes'; +import type { IAnimatedComponentInternalBase } from '../createAnimatedComponent/commonTypes'; +import type { HostInstance } from './types'; + +export function findHostInstance( + _ref: IAnimatedComponentInternalBase | InternalHostInstance +): HostInstance { + return null!; +} diff --git a/packages/react-native-reanimated/src/platform-specific/types.ts b/packages/react-native-reanimated/src/platform-specific/types.ts new file mode 100644 index 000000000000..950cb3444e3b --- /dev/null +++ b/packages/react-native-reanimated/src/platform-specific/types.ts @@ -0,0 +1,7 @@ +'use strict'; + +export type HostInstance = { + __internalInstanceHandle?: Record; + __nativeTag?: number; + _viewConfig?: Record; +}; diff --git a/packages/react-native-reanimated/src/platformFunctions/dispatchCommand.ts b/packages/react-native-reanimated/src/platformFunctions/dispatchCommand.ts index 63eec7bcfce7..b71cbd31c0d6 100644 --- a/packages/react-native-reanimated/src/platformFunctions/dispatchCommand.ts +++ b/packages/react-native-reanimated/src/platformFunctions/dispatchCommand.ts @@ -1,19 +1,11 @@ 'use strict'; + import { RuntimeKind } from 'react-native-worklets'; import { IS_JEST, logger, SHOULD_BE_USE_WEB } from '../common'; -import type { InstanceOrElement, ShadowNodeWrapper } from '../commonTypes'; -import type { - AnimatedRef, - AnimatedRefOnJS, - AnimatedRefOnUI, -} from '../hook/commonTypes'; - -type DispatchCommand = ( - animatedRef: AnimatedRef, - commandName: string, - args?: unknown[] -) => void; +import type { ShadowNodeWrapper } from '../commonTypes'; +import type { AnimatedRefOnJS, AnimatedRefOnUI } from '../hook/commonTypes'; +import type { DispatchCommand } from './types'; /** * Lets you synchronously call a command of a native component. diff --git a/packages/react-native-reanimated/src/platformFunctions/dispatchCommand.web.ts b/packages/react-native-reanimated/src/platformFunctions/dispatchCommand.web.ts index cf5bb5b2a27d..2d486898e68d 100644 --- a/packages/react-native-reanimated/src/platformFunctions/dispatchCommand.web.ts +++ b/packages/react-native-reanimated/src/platformFunctions/dispatchCommand.web.ts @@ -1,7 +1,16 @@ 'use strict'; import { logger } from '../common'; +import type { AnimatedRefOnJS, AnimatedRefOnUI } from '../hook/commonTypes'; +import type { DispatchCommand } from './types'; -export function dispatchCommand() { +function dispatchCommandWeb( + _animatedRef: AnimatedRefOnJS | AnimatedRefOnUI, + _commandName: string, + _args: Array = [] +) { logger.warn('dispatchCommand() is not supported on web.'); } + +export const dispatchCommand: DispatchCommand = + dispatchCommandWeb as DispatchCommand; diff --git a/packages/react-native-reanimated/src/platformFunctions/findNodeHandle.ts b/packages/react-native-reanimated/src/platformFunctions/findNodeHandle.ts index b4e540230095..5f56f9f3e261 100644 --- a/packages/react-native-reanimated/src/platformFunctions/findNodeHandle.ts +++ b/packages/react-native-reanimated/src/platformFunctions/findNodeHandle.ts @@ -1,4 +1,3 @@ 'use strict'; -import { findNodeHandle } from 'react-native'; -export { findNodeHandle }; +export { findNodeHandle } from 'react-native'; diff --git a/packages/react-native-reanimated/src/platformFunctions/findNodeHandle.web.ts b/packages/react-native-reanimated/src/platformFunctions/findNodeHandle.web.ts index d006db867245..c25d5618f307 100644 --- a/packages/react-native-reanimated/src/platformFunctions/findNodeHandle.web.ts +++ b/packages/react-native-reanimated/src/platformFunctions/findNodeHandle.web.ts @@ -1,8 +1,17 @@ 'use strict'; + import type { Component, ComponentClass } from 'react'; +import type { findNodeHandle as findNodeHandleRN } from 'react-native'; -export function findNodeHandle( - componentOrHandle: null | number | Component | ComponentClass +function findNodeHandleWeb( + componentOrHandle: + | null + | number + | Component + | ComponentClass ) { return componentOrHandle; } + +export const findNodeHandle: typeof findNodeHandleRN = + findNodeHandleWeb as typeof findNodeHandleRN; diff --git a/packages/react-native-reanimated/src/platformFunctions/types.ts b/packages/react-native-reanimated/src/platformFunctions/types.ts new file mode 100644 index 000000000000..50d0dbf74342 --- /dev/null +++ b/packages/react-native-reanimated/src/platformFunctions/types.ts @@ -0,0 +1,10 @@ +'use strict'; + +import type { InstanceOrElement } from '../commonTypes'; +import type { AnimatedRef } from '../hook/commonTypes'; + +export type DispatchCommand = ( + animatedRef: AnimatedRef, + commandName: string, + args?: unknown[] +) => void; diff --git a/packages/react-native-reanimated/tsconfig.json b/packages/react-native-reanimated/tsconfig.json index f70d69892588..8b800e86b2d3 100644 --- a/packages/react-native-reanimated/tsconfig.json +++ b/packages/react-native-reanimated/tsconfig.json @@ -1,9 +1,5 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "paths": { - "react-native-reanimated": ["./src"] - } - }, - "include": ["src"] + // To explore web types in your IDE you can temporarily change this line to: + // "extends": "./tsconfig.web.json" + "extends": "./tsconfig.native.json" } diff --git a/packages/react-native-reanimated/tsconfig.native.json b/packages/react-native-reanimated/tsconfig.native.json new file mode 100644 index 000000000000..e4fc4fa4d24f --- /dev/null +++ b/packages/react-native-reanimated/tsconfig.native.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "paths": { + "react-native-reanimated": ["./src"] + } + }, + "include": ["src"], + "exclude": ["**/*.web.ts", "**/*.web.tsx"] +} diff --git a/packages/react-native-reanimated/tsconfig.web.json b/packages/react-native-reanimated/tsconfig.web.json new file mode 100644 index 000000000000..7f759d10661a --- /dev/null +++ b/packages/react-native-reanimated/tsconfig.web.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.native.json", + "compilerOptions": { + "paths": { + "moduleSuffixes": [".web", ""] + } + }, + "exclude": [ + "**/*.native.ts", + "**/*.native.tsx", + "**/*.ios.ts", + "**/*.ios.tsx", + "**/*.android.ts", + "**/*.android.tsx" + ] +} diff --git a/packages/react-native-worklets/eslint.config.mjs b/packages/react-native-worklets/eslint.config.mjs index f8062771566f..cc44bbc07e0b 100644 --- a/packages/react-native-worklets/eslint.config.mjs +++ b/packages/react-native-worklets/eslint.config.mjs @@ -16,6 +16,11 @@ const config = tsEslint.config( languageOptions: { parserOptions: { tsconfigRootDir: import.meta.dirname, + project: [ + './tsconfig.json', + './tsconfig.web.json', + '../../tsconfig.json', + ], }, }, plugins: { diff --git a/packages/react-native-worklets/package.json b/packages/react-native-worklets/package.json index 73678f9a6672..0520e652e017 100644 --- a/packages/react-native-worklets/package.json +++ b/packages/react-native-worklets/package.json @@ -31,12 +31,12 @@ "lint:js": "eslint src && yarn prettier --check src", "lint:plugin": "yarn workspace babel-plugin-worklets lint", "test": "jest", - "type:check": "yarn type:check:src && yarn type:check:plugin && yarn type:check:app && yarn type:check:tests", - "type:check:src": "yarn tsc --noEmit", + "type:check": "yarn type:check:src:native && yarn type:check:src:web && yarn type:check:plugin && yarn type:check:app && yarn type:check:tests", + "type:check:src:native": "yarn tsc --noEmit", + "type:check:src:web": "yarn tsc --noEmit --project tsconfig.web.json", "type:check:app": "yarn workspace common-app type:check", "type:check:plugin": "yarn workspace babel-plugin-worklets type:check", - "type:check:tests": "../../scripts/test-ts.sh __typetests__", - "use-strict-check": "node ../../scripts/validate-use-strict.js" + "type:check:tests": "../../scripts/test-ts.sh __typetests__" }, "repository": { "type": "git", diff --git a/packages/react-native-worklets/plugin/eslint.config.mjs b/packages/react-native-worklets/plugin/eslint.config.mjs index 153e1e7053dd..1168527c8b71 100644 --- a/packages/react-native-worklets/plugin/eslint.config.mjs +++ b/packages/react-native-worklets/plugin/eslint.config.mjs @@ -11,6 +11,14 @@ import eslintConfig from '../../../eslint.config.mjs'; */ const config = tsEslint.config( ...eslintConfig, + { + languageOptions: { + parserOptions: { + project: ['./tsconfig.json', '../../../tsconfig.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, + }, { plugins: { 'simple-import-sort': simpleImportSort, @@ -25,9 +33,9 @@ const config = tsEslint.config( rules: { 'jsdoc/require-jsdoc': 'off', 'no-bitwise': 'off', - 'no-redeclare': 'warn' + 'no-redeclare': 'warn', }, - }, + } ); export default config; diff --git a/packages/react-native-worklets/plugin/tsconfig.json b/packages/react-native-worklets/plugin/tsconfig.json index 7c4829876a34..73b5f7c32c4b 100644 --- a/packages/react-native-worklets/plugin/tsconfig.json +++ b/packages/react-native-worklets/plugin/tsconfig.json @@ -13,6 +13,5 @@ "declaration": false, "noEmit": false }, - "include": ["src"], - "exclude": ["eslint.config.mjs"] + "include": ["src"] } diff --git a/packages/react-native-worklets/tsconfig.json b/packages/react-native-worklets/tsconfig.json index fd4ac617a0c3..8b800e86b2d3 100644 --- a/packages/react-native-worklets/tsconfig.json +++ b/packages/react-native-worklets/tsconfig.json @@ -1,9 +1,5 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "paths": { - "react-native-worklets": ["./src"] - } - }, - "include": ["src"] + // To explore web types in your IDE you can temporarily change this line to: + // "extends": "./tsconfig.web.json" + "extends": "./tsconfig.native.json" } diff --git a/packages/react-native-worklets/tsconfig.native.json b/packages/react-native-worklets/tsconfig.native.json new file mode 100644 index 000000000000..df26fe373a84 --- /dev/null +++ b/packages/react-native-worklets/tsconfig.native.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "paths": { + "react-native-worklets": ["./src"] + } + }, + "include": ["src"], + "exclude": ["**/*.web.ts", "**/*.web.tsx"] +} diff --git a/packages/react-native-worklets/tsconfig.web.json b/packages/react-native-worklets/tsconfig.web.json new file mode 100644 index 000000000000..7f759d10661a --- /dev/null +++ b/packages/react-native-worklets/tsconfig.web.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.native.json", + "compilerOptions": { + "paths": { + "moduleSuffixes": [".web", ""] + } + }, + "exclude": [ + "**/*.native.ts", + "**/*.native.tsx", + "**/*.ios.ts", + "**/*.ios.tsx", + "**/*.android.ts", + "**/*.android.tsx" + ] +} diff --git a/scripts/test-ts.sh b/scripts/test-ts.sh index 8500afc9acf5..fd77ebbd8967 100755 --- a/scripts/test-ts.sh +++ b/scripts/test-ts.sh @@ -1,18 +1,26 @@ #!/bin/bash -ARGS=$@ -FILES="" +ARGS=("$@") +FILES=() -for path in $ARGS; do - if [ -d $path ]; then - FILES_IN_DIR="" - FILES_IN_DIR+=$(ls $path | grep ".tsx\|.ts|.d.ts") - for file in $FILES_IN_DIR; do - FILES+="$path/$file " +for path in "${ARGS[@]}"; do + if [ -d "$path" ]; then + for file in "$path"/*.ts "$path"/*.tsx "$path"/*.d.ts; do + if [ -f "$file" ]; then + FILES+=("$file") + fi done else - FILES+="$path " + FILES+=("$path") fi done -yarn tsc --noEmit --target es6 --module ESNext --jsx react-native --skipLibCheck true --allowSyntheticDefaultImports true --moduleResolution node --esModuleInterop true --strict true --forceConsistentCasingInFileNames true --resolveJsonModule $FILES + +check_types() { + local suffixes="$1" + yarn tsc --noEmit --target es6 --module ESNext --jsx react-native --skipLibCheck true --allowSyntheticDefaultImports true --moduleResolution node --esModuleInterop true --strict true --forceConsistentCasingInFileNames true --moduleSuffixes "$suffixes" --resolveJsonModule "${FILES[@]}" +} + +check_types ".native,.ios,.android," + +check_types ".web," diff --git a/tsconfig.json b/tsconfig.json index ca382750a1d2..f41d77bb48c3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,9 @@ "resolveJsonModule": true, "allowJs": true, "checkJs": true, - "noEmit": true + "noEmit": true, + "moduleSuffixes": [".native", ".ios", ".android", ""] }, - "exclude": ["**/eslint.config.mjs"] + "include": [".", "**/.*"], + "exclude": ["**/__generatedWorklets"] } diff --git a/yarn.lock b/yarn.lock index 1061bd666f53..f61ec0f7e94c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15692,6 +15692,7 @@ __metadata: dependencies: "@types/react": "npm:19.2.2" common-app: "workspace:*" + eslint: "npm:9.37.0" prettier: "npm:3.6.2" react: "npm:19.1.1" react-native: "npm:0.82.0" @@ -30794,6 +30795,7 @@ __metadata: "@expo/metro-runtime": "npm:6.1.2" "@types/react": "npm:19.2.2" common-app: "workspace:*" + eslint: "npm:9.37.0" expo: "npm:54.0.13" prettier: "npm:3.6.2" react: "npm:19.1.1"