diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 06a3827..4fb322a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -12,7 +12,7 @@ Please include a summary of the change and which issue is fixed. Please also inc ## Checklist: - [ ] All tests are passing -- [ ] Type definitions, if updated, pass both `test-ts-defs` and `test-ts-usage` +- [ ] Type definitions, if updated, pass `types:check` and `pack:check` - [ ] Benchmark performance has not significantly decreased - [ ] Bundle size has not been significantly impacted - [ ] The bundle size badge has been updated to reflect the new size diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fe55caf..38fd666 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -102,15 +102,7 @@ $ pnpm run test-browser --browsers Chrome,Firefox,Safari ### Types -We validate our TypeScript `index.d.ts` with two steps: - -```sh -# Runs the TypeScript compiler over our types -$ pnpm run test-ts-defs - -# Runs our types through a sample TypeScript file -$ pnpm run test-ts-usage -``` +`pnpm types:check` type-checks `index.js` from its JSDoc and checks that the declarations it emits match `index.d.ts`. `pnpm pack:check` then compiles the type probe in `test/types/` against the packed package, as a CommonJS (`.cts`) and an ES module (`.mts`) consumer. Add a case there for any usage the types must keep supporting. ### Style diff --git a/package.json b/package.json index d7842f2..6cd6eea 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,7 @@ "test-browser": "karma start test/browser/karma.conf.js", "test-node": "mocha \"test/node/*.spec.js\"", "test-node-cov": "nyc mocha \"test/node/*.spec.js\"", - "test-ts-usage": "tsc --ignoreConfig --esModuleInterop --jsx react --noEmit test/typescript/sample-react-redux-usage.tsx test/typescript/sample-usage.tsx", - "test-ts-defs": "tsc --ignoreConfig --noEmit index.d.ts", - "test": "builder concurrent --buffer test-ts-usage test-ts-defs test-node-cov test-browser", + "test": "builder concurrent --buffer test-node-cov test-browser", "compress": "terser --compress --mangle=\"toplevel:true\" -- index.js", "size-min-gz": "pnpm -s compress | gzip -9 | wc -c", "changeset": "changeset", @@ -52,9 +50,7 @@ "@testing-library/dom": "^9.0.1", "@testing-library/preact": "^3.2.3", "@types/node": "^18.15.0", - "@types/react": "^16.9.35", - "@types/react-dom": "^16.9.8", - "@types/react-redux": "^7.1.25", + "@types/react": "^19.3.0", "assert": "^2.0.0", "babel-loader": "^9.1.2", "benchmark": "^2.1.4", @@ -80,10 +76,7 @@ "process": "^0.11.10", "publint": "0.3.25", "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-redux": "^8.0.5", "react-test-renderer": "^18.2.0", - "redux": "^4.2.1", "shallow-equal-fuzzy": "0.0.2", "sinon": "^15.0.1", "terser": "5.51.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d48d0f5..5fd45c9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -191,14 +191,8 @@ importers: specifier: ^18.15.0 version: 18.15.0 '@types/react': - specifier: ^16.9.35 - version: 16.9.35 - '@types/react-dom': - specifier: ^16.9.8 - version: 16.9.8 - '@types/react-redux': - specifier: ^7.1.25 - version: 7.1.25 + specifier: ^19.3.0 + version: 19.3.0 assert: specifier: ^2.0.0 version: 2.0.0 @@ -274,18 +268,9 @@ importers: react: specifier: ^18.2.0 version: 18.2.0 - react-dom: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) - react-redux: - specifier: ^8.0.5 - version: 8.0.5(@types/react-dom@16.9.8)(@types/react@16.9.35)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(redux@4.2.1) react-test-renderer: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) - redux: - specifier: ^4.2.1 - version: 4.2.1 shallow-equal-fuzzy: specifier: 0.0.2 version: 0.0.2 @@ -1334,29 +1319,14 @@ packages: '@types/estree@0.0.51': resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==} - '@types/hoist-non-react-statics@3.3.1': - resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==} - '@types/json-schema@7.0.11': resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} '@types/node@18.15.0': resolution: {integrity: sha512-z6nr0TTEOBGkzLGmbypWOGnpSpSIBorEhC4L+4HeQ2iezKCi4f77kyslRwvHeNitymGQ+oFyIWGP96l/DPSV9w==} - '@types/prop-types@15.7.3': - resolution: {integrity: sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==} - - '@types/react-dom@16.9.8': - resolution: {integrity: sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==} - - '@types/react-redux@7.1.25': - resolution: {integrity: sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg==} - - '@types/react@16.9.35': - resolution: {integrity: sha512-q0n0SsWcGc8nDqH2GJfWQWUOmZSJhXV64CjVN5SvcNti3TdEaA3AH0D8DwNmMdzjMAC/78tB8nAZIlV8yTz+zQ==} - - '@types/use-sync-external-store@0.0.3': - resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==} + '@types/react@19.3.0': + resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==} '@typescript/typescript-aix-ppc64@7.0.2': resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} @@ -1882,8 +1852,8 @@ packages: resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} engines: {node: '>=8'} - csstype@2.6.10: - resolution: {integrity: sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} custom-event@1.0.1: resolution: {integrity: sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==} @@ -2272,9 +2242,6 @@ packages: highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - html-encoding-sniffer@3.0.0: resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} engines: {node: '>=12'} @@ -2985,41 +2952,12 @@ packages: resolution: {integrity: sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==} engines: {node: '>= 0.8'} - react-dom@18.2.0: - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} - peerDependencies: - react: ^18.2.0 - - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - react-redux@8.0.5: - resolution: {integrity: sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==} - peerDependencies: - '@types/react': ^16.8 || ^17.0 || ^18.0 - '@types/react-dom': ^16.8 || ^17.0 || ^18.0 - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - react-native: '>=0.59' - redux: ^4 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - react-dom: - optional: true - react-native: - optional: true - redux: - optional: true - react-shallow-renderer@16.15.0: resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} peerDependencies: @@ -3042,9 +2980,6 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} - redux@4.2.1: - resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} - regenerate-unicode-properties@10.1.0: resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} engines: {node: '>=4'} @@ -3434,11 +3369,6 @@ packages: url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - use-sync-external-store@1.0.0: - resolution: {integrity: sha512-AFVsxg5GkFg8GDcxnl+Z0lMAz9rE8DGJCc28qnBuQF7lac57B5smLcT37aXpXIIPz75rW4g3eXHPjhHwdGskOw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0-rc - util@0.12.4: resolution: {integrity: sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==} @@ -4769,34 +4699,13 @@ snapshots: '@types/estree@0.0.51': {} - '@types/hoist-non-react-statics@3.3.1': - dependencies: - '@types/react': 16.9.35 - hoist-non-react-statics: 3.3.2 - '@types/json-schema@7.0.11': {} '@types/node@18.15.0': {} - '@types/prop-types@15.7.3': {} - - '@types/react-dom@16.9.8': - dependencies: - '@types/react': 16.9.35 - - '@types/react-redux@7.1.25': + '@types/react@19.3.0': dependencies: - '@types/hoist-non-react-statics': 3.3.1 - '@types/react': 16.9.35 - hoist-non-react-statics: 3.3.2 - redux: 4.2.1 - - '@types/react@16.9.35': - dependencies: - '@types/prop-types': 15.7.3 - csstype: 2.6.10 - - '@types/use-sync-external-store@0.0.3': {} + csstype: 3.2.3 '@typescript/typescript-aix-ppc64@7.0.2': optional: true @@ -5315,7 +5224,7 @@ snapshots: dependencies: cssom: 0.3.8 - csstype@2.6.10: {} + csstype@3.2.3: {} custom-event@1.0.1: {} @@ -5681,10 +5590,6 @@ snapshots: highlight.js@10.7.3: {} - hoist-non-react-statics@3.3.2: - dependencies: - react-is: 16.13.1 - html-encoding-sniffer@3.0.0: dependencies: whatwg-encoding: 2.0.0 @@ -6488,33 +6393,10 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 - react-dom@18.2.0(react@18.2.0): - dependencies: - loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.23.0 - - react-is@16.13.1: {} - react-is@17.0.2: {} react-is@18.2.0: {} - react-redux@8.0.5(@types/react-dom@16.9.8)(@types/react@16.9.35)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(redux@4.2.1): - dependencies: - '@babel/runtime': 7.21.5 - '@types/hoist-non-react-statics': 3.3.1 - '@types/use-sync-external-store': 0.0.3 - hoist-non-react-statics: 3.3.2 - react: 18.2.0 - react-is: 18.2.0 - use-sync-external-store: 1.0.0(react@18.2.0) - optionalDependencies: - '@types/react': 16.9.35 - '@types/react-dom': 16.9.8 - react-dom: 18.2.0(react@18.2.0) - redux: 4.2.1 - react-shallow-renderer@16.15.0(react@18.2.0): dependencies: object-assign: 4.1.1 @@ -6538,10 +6420,6 @@ snapshots: readdirp@4.1.2: {} - redux@4.2.1: - dependencies: - '@babel/runtime': 7.21.5 - regenerate-unicode-properties@10.1.0: dependencies: regenerate: 1.4.2 @@ -6935,10 +6813,6 @@ snapshots: querystringify: 2.2.0 requires-port: 1.0.0 - use-sync-external-store@1.0.0(react@18.2.0): - dependencies: - react: 18.2.0 - util@0.12.4: dependencies: inherits: 2.0.4 diff --git a/scripts/pack-check.mjs b/scripts/pack-check.mjs index 91a0b3c..dd74d0e 100644 --- a/scripts/pack-check.mjs +++ b/scripts/pack-check.mjs @@ -6,13 +6,17 @@ // 2. Runs publint and attw (`@arethetypeswrong/cli`) on it. // 3. Installs it outside the repo and loads it with `require()` and // `import()`: both must give the same working `isEqual` function. -// 4. Compares it against `pack-snapshot.json`: manifest fields, file list, +// 4. Type probe: compiles `test/types/` against the installed package with +// TypeScript (`module: nodenext`), as a CommonJS (`.cts`) and an ES module +// (`.mts`) consumer. +// 5. Compares it against `pack-snapshot.json`: manifest fields, file list, // how attw resolves the types, `index.d.ts`, and `index.js` minified // without comments. In 3.x only formatting and comments may change in // `index.js` (see CONTRIBUTING). Pass `--update` to rewrite the snapshot // after an intended change. import { execFileSync } from 'node:child_process'; import fs from 'node:fs'; +import { createRequire } from 'node:module'; import os from 'node:os'; import path from 'node:path'; import { publint } from 'publint'; @@ -61,6 +65,7 @@ const rootDir = path.resolve(import.meta.dirname, '..'); const workDir = path.join(rootDir, 'node_modules/.cache/pack-check'); const snapshotPath = path.join(rootDir, 'pack-snapshot.json'); const failures = []; +const require = createRequire(import.meta.url); const run = (cmd, cmdArgs, opts = {}) => execFileSync(cmd, cmdArgs, { encoding: 'utf8', ...opts }); @@ -198,6 +203,40 @@ console.log(JSON.stringify(errors)); ); } + // Type probe. Copy the fixtures next to the installed package, with a + // tsconfig that clears the editor-only `paths`, and link in the React types. + const probeSrc = path.join(rootDir, 'test/types'); + for (const file of fs.readdirSync(probeSrc)) { + if (file !== 'tsconfig.json') + fs.copyFileSync(path.join(probeSrc, file), path.join(installRoot, file)); + } + fs.writeFileSync( + path.join(installRoot, 'tsconfig.json'), + JSON.stringify({ + extends: path.join(probeSrc, 'tsconfig.json'), + compilerOptions: { paths: {} }, + include: ['*.ts', '*.cts', '*.mts'], + }) + ); + fs.mkdirSync(path.join(modulesDir, '@types')); + fs.symlinkSync( + fs.realpathSync(path.join(rootDir, 'node_modules/@types/react')), + path.join(modulesDir, '@types/react'), + 'junction' + ); + const tsc = path.join( + path.dirname(require.resolve('typescript/package.json')), + 'bin/tsc' + ); + try { + run(process.execPath, [tsc, '--project', installRoot], { + cwd: installRoot, + stdio: ['ignore', 'pipe', 'pipe'], + }); + } catch (err) { + failures.push(`Type probe (test/types) failed:\n${err.stdout.trim()}`); + } + // Published code. Minified without comments, so formatting and comments // don't count, and pretty-printed one statement per line, so a change shows // up as a readable diff. Without `compress`, the output depends only on the diff --git a/test/types/probe.cts b/test/types/probe.cts new file mode 100644 index 0000000..bd8aec5 --- /dev/null +++ b/test/types/probe.cts @@ -0,0 +1,9 @@ +// Type probe: a CommonJS consumer (`.cts`). Both import forms must give 3.2.2's +// signature. The usage cases are in `probe.mts`. +import isEqualRequire = require('react-fast-compare'); +import isEqualDefault from 'react-fast-compare'; +import type { Equals, Signature } from './signature.js'; + +export const requireOk: Equals = true; +export const defaultOk: Equals = true; +export const result: boolean = isEqualRequire({ a: 1 }, { a: 1 }); diff --git a/test/types/probe.mts b/test/types/probe.mts new file mode 100644 index 0000000..f1d5b44 --- /dev/null +++ b/test/types/probe.mts @@ -0,0 +1,47 @@ +// Type probe: an ES module consumer (`.mts`), with the ways people use +// `isEqual`. `pnpm pack:check` compiles it against the packed tarball. +import * as React from 'react'; +import isEqual from 'react-fast-compare'; +import type { Equals, Signature } from './signature.js'; + +export const defaultOk: Equals = true; + +type Props = { id: string; text: string }; + +// `React.memo` comparison function. +const Item = (props: Props) => props.text; +export const MemoItem = React.memo(Item, isEqual); + +// `shouldComponentUpdate`. +export class ItemClass extends React.Component { + shouldComponentUpdate(nextProps: Readonly) { + return !isEqual(this.props, nextProps); + } + + render() { + return this.props.text; + } +} + +// Equality callbacks shaped `(a: T, b: T) => boolean`, as in react-redux's +// `useSelector` or zustand's `useStoreWithEqualityFn`. +declare function useSelector( + selector: (state: S) => T, + equalityFn?: (a: T, b: T) => boolean +): T; +export const count: number = useSelector( + (state: { items: string[] }) => state.items.length, + isEqual +); + +// A `false` result doesn't narrow `prev` to `never` (#130). +export function changedText(prev: Props, next: Props): string | null { + if (isEqual(prev, next)) return null; + return prev.text; +} + +// @ts-expect-error: returns `boolean`, not a string. +export const notString: string = isEqual(1, 2); + +// @ts-expect-error: takes two arguments. +export const oneArg = isEqual(1); diff --git a/test/types/signature.ts b/test/types/signature.ts new file mode 100644 index 0000000..a9d4f8a --- /dev/null +++ b/test/types/signature.ts @@ -0,0 +1,9 @@ +// What every consumer must see for `isEqual`, however it imports it: 3.2.2's +// signature. A type guard (`a is B`, #130) or a narrower return type fails. +export type Signature = (a: A, b: B) => boolean; + +// `true` only if X and Y are the same type. +export type Equals = + (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 + ? true + : false; diff --git a/test/types/tsconfig.json b/test/types/tsconfig.json new file mode 100644 index 0000000..dc871be --- /dev/null +++ b/test/types/tsconfig.json @@ -0,0 +1,14 @@ +{ + // Type probe settings. `pnpm pack:check` copies these files next to the + // installed tarball and compiles them with `paths` cleared, so the probe + // sees the published package. `paths` here only serves editors. + "compilerOptions": { + "lib": ["ES2020", "DOM"], + "module": "nodenext", + "noEmit": true, + "paths": { "react-fast-compare": ["../../index.d.ts"] }, + "strict": true, + "types": [] + }, + "include": ["*.ts", "*.cts", "*.mts"] +} diff --git a/test/typescript/sample-react-redux-usage.tsx b/test/typescript/sample-react-redux-usage.tsx deleted file mode 100644 index 1711708..0000000 --- a/test/typescript/sample-react-redux-usage.tsx +++ /dev/null @@ -1,46 +0,0 @@ -// This file exists to test our types against sample user code -// This is compiled using `tsc` in our `test-ts-usage` script -import React from 'react'; -import ReactDOM from 'react-dom'; -import { Provider, useSelector } from 'react-redux'; -import { createStore } from 'redux'; - -import equal from '../../index.js'; - -type IState = { - items: string[]; -}; - -type IAction = { - type: string; - payload: any; -}; - -const initialState: IState = { - items: [], -}; - -const reducer = (state: IState = initialState, action: IAction) => { - return state; -}; - -const lengthSelector = (state: IState): number => state.items.length; - -const store = createStore(reducer, initialState); - -function Test() { - const length = useSelector(lengthSelector, equal); - return ( -
- Testing react-redux useSelector. There are - {length.toExponential()} items. -
- ); -} - -ReactDOM.render( - - - , - document.getElementById('root') -); diff --git a/test/typescript/sample-usage.tsx b/test/typescript/sample-usage.tsx deleted file mode 100644 index 0bd46e1..0000000 --- a/test/typescript/sample-usage.tsx +++ /dev/null @@ -1,48 +0,0 @@ -// This file exists to test our types against sample user code -// This is compiled using `tsc` in our `test-ts-usage` script -import React from 'react'; -import equal from '../../index.js'; - -type ITodo = { - text: string; - id: string; -}; - -const testArr: ITodo[] = [ - { text: 'green', id: '23' }, - { text: 'sunshine', id: '1' }, - { text: 'mountain', id: '11' }, - { text: 'air', id: '8' }, - { text: 'plants', id: '9' }, -]; - -type IProps = { - todo: ITodo; -}; - -class TestChild extends React.Component { - shouldComponentUpdate(nextProps: IProps) { - return !equal(this.props, nextProps); - } - - render() { - const todo = this.props.todo; - return
{todo.text}
; - } -} - -// `equal` must return a plain `boolean`, not a type guard (`a is B`): after a -// `false` result, a guard narrows `prev` to `never`, so `prev.text` would not -// compile (#130). -export function changedText(prev: ITodo, next: ITodo): string | null { - if (equal(prev, next)) return null; - return prev.text; -} - -class TestContainer extends React.Component { - render() { - return testArr.map((item) => ); - } -} - -export default TestContainer; diff --git a/test/typescript/tsconfig.json b/test/typescript/tsconfig.json deleted file mode 100644 index b49e850..0000000 --- a/test/typescript/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "jsx": "react", - "target": "ES6", - "allowSyntheticDefaultImports": true - } -} diff --git a/test/typescript/tsconfig.tsbuildinfo b/test/typescript/tsconfig.tsbuildinfo deleted file mode 100644 index eef12e0..0000000 --- a/test/typescript/tsconfig.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"version":"7.0.2","root":[[44,45]],"packageJsons":["../../node_modules/.pnpm/@types+hoist-non-react-statics@3.3.1/node_modules/@types/hoist-non-react-statics/package.json","../../node_modules/.pnpm/@types+prop-types@15.7.3/node_modules/@types/prop-types/package.json","../../node_modules/.pnpm/@types+react-dom@16.9.8/node_modules/@types/react-dom/package.json","../../node_modules/.pnpm/@types+react@16.9.35/node_modules/@types/react/package.json","../../node_modules/.pnpm/@types+use-sync-external-store@0.0.3/node_modules/@types/use-sync-external-store/package.json","../../node_modules/.pnpm/csstype@2.6.10/node_modules/csstype/package.json","../../node_modules/.pnpm/hoist-non-react-statics@3.3.2/node_modules/hoist-non-react-statics/package.json","../../node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/package.json","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/package.json","../../node_modules/.pnpm/react@18.2.0/node_modules/react/package.json","../../node_modules/.pnpm/redux@4.2.1/node_modules/redux/package.json","../../node_modules/.pnpm/use-sync-external-store@1.0.0_react@18.2.0/node_modules/use-sync-external-store/package.json","../../package.json"],"missingPackageJsons":["../../node_modules/.pnpm/@types+hoist-non-react-statics@3.3.1/node_modules/react/package.json","../../node_modules/.pnpm/@types+react-dom@16.9.8/node_modules/react/package.json","../../node_modules/.pnpm/@types+react@16.9.35/node_modules/prop-types/package.json","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/@types/use-sync-external-store/with-selector/package.json","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-native/package.json","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/components/package.json","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/connect/package.json","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/hooks/package.json","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/package.json","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/utils/package.json","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/use-sync-external-store/with-selector/package.json"],"fileNames":["lib.es6.d.ts","lib.es5.d.ts","lib.es2015.d.ts","lib.dom.d.ts","lib.dom.iterable.d.ts","lib.webworker.importscripts.d.ts","lib.scripthost.d.ts","lib.es2015.core.d.ts","lib.es2015.collection.d.ts","lib.es2015.generator.d.ts","lib.es2015.iterable.d.ts","lib.es2015.promise.d.ts","lib.es2015.proxy.d.ts","lib.es2015.reflect.d.ts","lib.es2015.symbol.d.ts","lib.es2015.symbol.wellknown.d.ts","lib.es2018.asynciterable.d.ts","lib.decorators.d.ts","lib.decorators.legacy.d.ts","../../node_modules/.pnpm/@types+react@16.9.35/node_modules/@types/react/global.d.ts","../../node_modules/.pnpm/csstype@2.6.10/node_modules/csstype/index.d.ts","../../node_modules/.pnpm/@types+prop-types@15.7.3/node_modules/@types/prop-types/index.d.ts","../../node_modules/.pnpm/@types+react@16.9.35/node_modules/@types/react/index.d.ts","../../node_modules/.pnpm/@types+react-dom@16.9.8/node_modules/@types/react-dom/index.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/utils/reactbatchedupdates.d.ts","../../node_modules/.pnpm/redux@4.2.1/node_modules/redux/index.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/utils/subscription.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/components/context.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/components/provider.d.ts","../../node_modules/.pnpm/@types+hoist-non-react-statics@3.3.1/node_modules/@types/hoist-non-react-statics/index.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/types.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/connect/selectorfactory.d.ts","../../node_modules/.pnpm/@types+use-sync-external-store@0.0.3/node_modules/@types/use-sync-external-store/index.d.ts","../../node_modules/.pnpm/@types+use-sync-external-store@0.0.3/node_modules/@types/use-sync-external-store/with-selector.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/utils/usesyncexternalstore.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/components/connect.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/hooks/usedispatch.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/hooks/useselector.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/hooks/usestore.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/utils/shallowequal.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/exports.d.ts","../../node_modules/.pnpm/react-redux@8.0.5_@types+react-dom@16.9.8_@types+react@16.9.35_react-dom@18.2.0_react@18.2.0__react@18.2.0_redux@4.2.1/node_modules/react-redux/es/index.d.ts","../../index.d.ts","./sample-react-redux-usage.tsx","./sample-usage.tsx"],"fileInfos":["d5989fd19a90632be70bb582dce051c9",{"version":"16934abaab7026ac114da441aabea1a0","affectsGlobalScope":true,"impliedNodeFormat":1},"d4306fb2e47f74835e8674ffac07d76f",{"version":"aae8996e8b5684814785a42cbbefcd79","affectsGlobalScope":true,"impliedNodeFormat":1},"abad6dd56cc8caf095c165df8124d237",{"version":"2a9941db0809c9ad0e8837ed629b1dcc","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"d051b93324f36bcc68d152a5ca0988cd","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"926204c28cd3d073865348473ae28d2e","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"f25e42c801b2cb3cf2b39792006a9beb","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"6344b55f26a4e81d9608777dbfb877dd","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"3c0ed28e53d3695b363e256ec1c023fd","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"4c2761daba7f17141c25baa0821ac5da","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"b87656acabd63e69379ff6ffcfe52fc7","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"597469522da047a5af5222cc6989f405","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"1708ea4d34dc37fadadc63ca01127e80","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"55d97a8c6fbf34a30450a7b1e5f7a298","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"b612fb5cf8e5d964b92063a75207632a","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"f64453cbf9671f28158677fa5c43967a","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"33f317af5428801f944a478d2c1e38e5","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"7376cd32b4c24f5e3471d538cce0a6cc","affectsGlobalScope":true,"impliedNodeFormat":1},"cdab56a98e2799503649ed9fb828354c","6ed0c2b51741b7f9a464f81ffebf1c15",{"version":"b231ecbcee7c60c29c58ecc0b3bfa420","affectsGlobalScope":true,"impliedNodeFormat":1},"eaa1fde8bf16bbb589f282c92dbe56da","6a0b6b4b392a782f2d7e9fcf18d1259f",{"version":"0139c837c4b77e8bf9ca4862b3b5b402","affectsGlobalScope":true,"impliedNodeFormat":1},"c7476a36ac17674d9e6348949a4a020f","744d549e39fb2aec18f51001adc8b7f2","a285482b1ee242199f172dd27737ada2","0c7a2d28d5e48b8d78bac1e63b1293b7","4b1d59f626811623ae04ac3f34d78970","2c5373be10f09cd4b67fc4ada58cd906","b51da9fbf09aeb13e9e40847793e2d87","5292475dc78e70eac35362920b4e776e","b139874f766ce4041d64328ecdbd883e","9578593fa99ef16544d5c98a0db00f95","cb849316fde74b6b70fe20b89a3481d5","eaae60aa7f1223634b9a2d1f7f95b222","20ac72c4b5089e0f5c020290d209afef","6f913952671301583d38d307911c92a1","215d56c4b8210fe5446cb789faed48d6","cfb792ede0cfdc3114e476f29a0735f8","1df46f12d4648e46aed5be301a7a567b","8b49fbc742068ff24482c2f6db4b34c3","494a105c55f9d709cd324beb355dfa20"],"fileIdsList":[[23],[20,21,22],[26,28,31,32,35],[23,26,27],[23,26,28],[23,26,31],[27,28,29,31,32,36,37,38,39,40],[23,26,28,31,35],[25,41],[23,26,30,36],[24],[33,34],[23,24,26,42,43],[23,43]],"options":{"composite":true,"jsx":3,"target":2,"allowSyntheticDefaultImports":true},"referencedMap":[[30,1],[24,1],[23,2],[36,3],[28,4],[29,5],[32,6],[41,7],[37,5],[38,8],[39,5],[42,9],[31,10],[25,11],[35,12],[44,13],[45,14]],"affectedFilesPendingEmit":[[44,17],[45,17]],"emitSignatures":[44,45]} \ No newline at end of file