From e497f82ffc872125d27b4cef01f0e54dba9131a2 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Sat, 22 Feb 2025 21:54:08 +0100 Subject: [PATCH 1/2] Use default tsconfig for tests --- __tests__/Conversion.ts | 20 ++++++++++++-------- __tests__/KeyedSeq.ts | 9 +++++++++ __tests__/Map.ts | 2 +- __tests__/Seq.ts | 2 +- __tests__/Set.ts | 2 +- __tests__/merge.ts | 17 ++++++++++------- __tests__/tsconfig.json | 11 ++++------- resources/jestPreprocessor.js | 4 ++-- 8 files changed, 40 insertions(+), 27 deletions(-) diff --git a/__tests__/Conversion.ts b/__tests__/Conversion.ts index 1da714e134..ca0f717f07 100644 --- a/__tests__/Conversion.ts +++ b/__tests__/Conversion.ts @@ -114,7 +114,7 @@ describe('Conversion', () => { }); it('Converts deep JSON with custom conversion', () => { - const seq = fromJS(js, function (key, sequence) { + const seq = fromJS(js, function (this, key, sequence) { if (key === 'point') { // @ts-expect-error -- to convert to real typing return new Point(sequence); @@ -130,13 +130,17 @@ describe('Conversion', () => { it('Converts deep JSON with custom conversion including keypath if requested', () => { const paths: Array | undefined> = []; // eslint-disable-next-line @typescript-eslint/no-unused-vars - const seq1 = fromJS(js, function (key, sequence, keypath) { - expect(arguments.length).toBe(3); - paths.push(keypath); - return Array.isArray(this[key]) - ? sequence.toList() - : sequence.toOrderedMap(); - }); + const seq1 = fromJS( + js, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + function (this: typeof js, key: any, sequence, keypath) { + expect(arguments.length).toBe(3); + paths.push(keypath); + return Array.isArray(this[key]) + ? sequence.toList() + : sequence.toOrderedMap(); + } + ); expect(paths).toEqual([ [], ['deepList'], diff --git a/__tests__/KeyedSeq.ts b/__tests__/KeyedSeq.ts index 0a14ebb3d9..d716cf9685 100644 --- a/__tests__/KeyedSeq.ts +++ b/__tests__/KeyedSeq.ts @@ -1,5 +1,6 @@ import { Range, Seq } from 'immutable'; import * as jasmineCheck from 'jasmine-check'; +import invariant from '../src/utils/invariant'; jasmineCheck.install(); @@ -36,6 +37,10 @@ describe('KeyedSeq', () => { const [indexed0, indexed1] = seq .partition(isEven) .map((part) => part.skip(10).take(5)); + + invariant(indexed0, 'indexed0 is not undefined'); + invariant(indexed1, 'indexed0 is not undefined'); + expect(indexed0.entrySeq().toArray()).toEqual([ [0, 21], [1, 23], @@ -64,6 +69,10 @@ describe('KeyedSeq', () => { const [keyed0, keyed1] = keyed .partition(isEven) .map((part) => part.skip(10).take(5)); + + invariant(keyed0, 'keyed0 is not undefined'); + invariant(keyed1, 'keyed1 is not undefined'); + expect(keyed0.entrySeq().toArray()).toEqual([ [21, 21], [23, 23], diff --git a/__tests__/Map.ts b/__tests__/Map.ts index 85e84de05e..39cc8fcb3e 100644 --- a/__tests__/Map.ts +++ b/__tests__/Map.ts @@ -449,7 +449,7 @@ describe('Map', () => { it('uses toString on keys and values', () => { class A extends Record({ x: null as number | null }) { - toString() { + override toString() { return this.x; } } diff --git a/__tests__/Seq.ts b/__tests__/Seq.ts index d2a954a7af..392ac23615 100644 --- a/__tests__/Seq.ts +++ b/__tests__/Seq.ts @@ -38,7 +38,7 @@ describe('Seq', () => { }); it('accepts arbitrary objects', () => { - function Foo() { + function Foo(this: { bar: string; baz: string }) { this.bar = 'bar'; this.baz = 'baz'; } diff --git a/__tests__/Set.ts b/__tests__/Set.ts index ff4997c1f7..ebccca9223 100644 --- a/__tests__/Set.ts +++ b/__tests__/Set.ts @@ -304,7 +304,7 @@ describe('Set', () => { Symbol('a'), Symbol('b'), Symbol('c'), - ]; + ] as const; const symbolSet = Set(manySymbols); expect(symbolSet.size).toBe(12); diff --git a/__tests__/merge.ts b/__tests__/merge.ts index af3b0c8453..30aa2b7255 100644 --- a/__tests__/merge.ts +++ b/__tests__/merge.ts @@ -241,15 +241,18 @@ describe('merge', () => { ).toBe(true); }); - const map = { type: 'Map', value: Map({ b: 5, c: 9 }) }; - const object = { type: 'object', value: { b: 7, d: 12 } }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + type TypeValue = { type: any; value: any }; + + const map: TypeValue = { type: 'Map', value: Map({ b: 5, c: 9 }) }; + const object: TypeValue = { type: 'object', value: { b: 7, d: 12 } }; const RecordFactory = Record({ a: 1, b: 2 }); - const record = { type: 'Record', value: RecordFactory({ b: 3 }) }; - const list = { type: 'List', value: List(['5']) }; - const array = { type: 'array', value: ['9'] }; - const set = { type: 'Set', value: Set('3') }; + const record: TypeValue = { type: 'Record', value: RecordFactory({ b: 3 }) }; + const list: TypeValue = { type: 'List', value: List(['5']) }; + const array: TypeValue = { type: 'array', value: ['9'] }; + const set: TypeValue = { type: 'Set', value: Set('3') }; - const incompatibleTypes = [ + const incompatibleTypes: Array<[TypeValue, TypeValue]> = [ [map, list], [map, array], [map, set], diff --git a/__tests__/tsconfig.json b/__tests__/tsconfig.json index 1de3301b83..4df4b5b796 100644 --- a/__tests__/tsconfig.json +++ b/__tests__/tsconfig.json @@ -1,12 +1,9 @@ { + "extends": "../tsconfig.json", "compilerOptions": { - "noEmit": true, - // TODO: add additional strictness - "strictNullChecks": true, - "strictFunctionTypes": true, - "target": "esnext", - "moduleResolution": "node", - "skipLibCheck": true, + // TODO remove those "false" value that make the code less strict + "noImplicitAny": false, + "verbatimModuleSyntax": false, "paths": { "immutable": ["../type-definitions/immutable.d.ts"], "jasmine-check": ["../resources/jasmine-check.d.ts"] diff --git a/resources/jestPreprocessor.js b/resources/jestPreprocessor.js index 5ea6aa5036..c334f071cd 100644 --- a/resources/jestPreprocessor.js +++ b/resources/jestPreprocessor.js @@ -3,11 +3,11 @@ const makeSynchronous = require('make-synchronous'); const TYPESCRIPT_OPTIONS = { noEmitOnError: true, - target: typescript.ScriptTarget.ES2015, + target: typescript.ScriptTarget.ES2022, module: typescript.ModuleKind.CommonJS, - strictNullChecks: true, sourceMap: true, inlineSourceMap: true, + esModuleInterop: true, }; function transpileTypeScript(src, path) { From 90a3ee824d3bc3a9f5c2b5baa3135f6f0f6e3822 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Tue, 25 Feb 2025 09:36:03 +0100 Subject: [PATCH 2/2] start typing __tests__ dir --- __tests__/ArraySeq.ts | 2 +- __tests__/Conversion.ts | 50 +++++++++++++++++++++++++++---------- __tests__/KeyedSeq.ts | 36 ++++++++++++++------------ __tests__/OrderedSet.ts | 2 +- __tests__/Predicates.ts | 2 +- __tests__/Seq.ts | 2 +- __tests__/functional/get.ts | 7 ++++-- __tests__/groupBy.ts | 2 +- __tests__/hash.ts | 16 +++++++----- __tests__/join.ts | 2 +- __tests__/tsconfig.json | 1 + __tests__/zip.ts | 2 +- 12 files changed, 80 insertions(+), 44 deletions(-) diff --git a/__tests__/ArraySeq.ts b/__tests__/ArraySeq.ts index 85b526edbd..77e7716947 100644 --- a/__tests__/ArraySeq.ts +++ b/__tests__/ArraySeq.ts @@ -29,7 +29,7 @@ describe('ArraySequence', () => { it('efficiently chains iteration methods', () => { const i = Seq('abcdefghijklmnopqrstuvwxyz'.split('')); - function studly(letter, index) { + function studly(letter: string, index: number): string { return index % 2 === 0 ? letter : letter.toUpperCase(); } const result = i diff --git a/__tests__/Conversion.ts b/__tests__/Conversion.ts index ca0f717f07..b0e10abd6e 100644 --- a/__tests__/Conversion.ts +++ b/__tests__/Conversion.ts @@ -1,4 +1,12 @@ -import { fromJS, is, List, Map, OrderedMap, Record } from 'immutable'; +import { + fromJS, + is, + List, + Map, + OrderedMap, + Record, + type Collection, +} from 'immutable'; import * as jasmineCheck from 'jasmine-check'; jasmineCheck.install(); @@ -114,15 +122,25 @@ describe('Conversion', () => { }); it('Converts deep JSON with custom conversion', () => { - const seq = fromJS(js, function (this, key, sequence) { - if (key === 'point') { - // @ts-expect-error -- to convert to real typing - return new Point(sequence); + const seq = fromJS( + js, + function ( + this: typeof js, + key: PropertyKey, + sequence: + | Collection.Keyed + | Collection.Indexed + ) { + if (key === 'point') { + // @ts-expect-error -- to convert to real typing + return new Point(sequence); + } + // @ts-expect-error unknown any type + return Array.isArray(this[key]) + ? sequence.toList() + : sequence.toOrderedMap(); } - return Array.isArray(this[key]) - ? sequence.toList() - : sequence.toOrderedMap(); - }); + ); expect(seq).toEqual(immutableOrderedData); expect(seq.toString()).toEqual(immutableOrderedDataString); }); @@ -136,6 +154,7 @@ describe('Conversion', () => { function (this: typeof js, key: any, sequence, keypath) { expect(arguments.length).toBe(3); paths.push(keypath); + // @ts-expect-error unknown any type return Array.isArray(this[key]) ? sequence.toList() : sequence.toOrderedMap(); @@ -196,10 +215,15 @@ describe('Conversion', () => { expect(fromJS('string')).toEqual('string'); }); - check.it('toJS isomorphic value', { maxSize: 30 }, [gen.JSONValue], (v) => { - const imm = fromJS(v); - expect(imm && imm.toJS ? imm.toJS() : imm).toEqual(v); - }); + check.it( + 'toJS isomorphic value', + { maxSize: 30 }, + [gen.JSONValue], + (v: object) => { + const imm = fromJS(v); + expect(imm && imm.toJS ? imm.toJS() : imm).toEqual(v); + } + ); it('Explicitly convert values to string using String constructor', () => { expect(() => fromJS({ foo: Symbol('bar') }) + '').not.toThrow(); diff --git a/__tests__/KeyedSeq.ts b/__tests__/KeyedSeq.ts index d716cf9685..feee1728a9 100644 --- a/__tests__/KeyedSeq.ts +++ b/__tests__/KeyedSeq.ts @@ -5,24 +5,28 @@ import invariant from '../src/utils/invariant'; jasmineCheck.install(); describe('KeyedSeq', () => { - check.it('it iterates equivalently', [gen.array(gen.int)], (ints) => { - const seq = Seq(ints); - const keyed = seq.toKeyedSeq(); - - const seqEntries = seq.entries(); - const keyedEntries = keyed.entries(); - - let seqStep; - let keyedStep; - do { - seqStep = seqEntries.next(); - keyedStep = keyedEntries.next(); - expect(keyedStep).toEqual(seqStep); - } while (!seqStep.done); - }); + check.it( + 'it iterates equivalently', + [gen.array(gen.int)], + (ints: Array) => { + const seq = Seq(ints); + const keyed = seq.toKeyedSeq(); + + const seqEntries = seq.entries(); + const keyedEntries = keyed.entries(); + + let seqStep; + let keyedStep; + do { + seqStep = seqEntries.next(); + keyedStep = keyedEntries.next(); + expect(keyedStep).toEqual(seqStep); + } while (!seqStep.done); + } + ); it('maintains keys', () => { - const isEven = (x) => x % 2 === 0; + const isEven = (x: number): boolean => x % 2 === 0; const seq = Range(0, 100); // This is what we expect for IndexedSequences diff --git a/__tests__/OrderedSet.ts b/__tests__/OrderedSet.ts index b85dc16bff..166fa0847a 100644 --- a/__tests__/OrderedSet.ts +++ b/__tests__/OrderedSet.ts @@ -62,7 +62,7 @@ describe('OrderedSet', () => { * @see https://github.com/immutable-js/immutable-js/issues/1716 */ it('handles `subtract` when Set contains >=32 elements', () => { - const fillArray = (nb) => + const fillArray = (nb: number) => Array(nb) .fill(1) .map((el, i) => i + 1); diff --git a/__tests__/Predicates.ts b/__tests__/Predicates.ts index 40136c71b9..2574adec76 100644 --- a/__tests__/Predicates.ts +++ b/__tests__/Predicates.ts @@ -42,7 +42,7 @@ describe('isValueObject', () => { this.v = val; } - equals(other) { + equals(other: MyValueType) { return Boolean(other && this.v === other.v); } diff --git a/__tests__/Seq.ts b/__tests__/Seq.ts index 392ac23615..254ee7f509 100644 --- a/__tests__/Seq.ts +++ b/__tests__/Seq.ts @@ -30,7 +30,7 @@ describe('Seq', () => { }); it('accepts an object with a next property', () => { - expect(Seq({ a: 1, b: 2, next: (_) => _ }).size).toBe(3); + expect(Seq({ a: 1, b: 2, next: (_: unknown) => _ }).size).toBe(3); }); it('accepts a collection string', () => { diff --git a/__tests__/functional/get.ts b/__tests__/functional/get.ts index fdb687302b..57efdd1f04 100644 --- a/__tests__/functional/get.ts +++ b/__tests__/functional/get.ts @@ -1,4 +1,5 @@ import { get, Map, List, Range } from 'immutable'; +import invariant from '../../src/utils/invariant'; describe('get', () => { it('for immutable structure', () => { @@ -25,8 +26,10 @@ describe('get', () => { { x: 'xx', y: 'yy', - get: function (key: string) { - return `${this[key].toUpperCase()}`; + get: function (this, key: string) { + invariant(typeof this[key] === 'string', 'this[key] is a string'); + + return this[key].toUpperCase(); }, }, 'x' diff --git a/__tests__/groupBy.ts b/__tests__/groupBy.ts index b759661711..264a5bf0ac 100644 --- a/__tests__/groupBy.ts +++ b/__tests__/groupBy.ts @@ -31,7 +31,7 @@ describe('groupBy', () => { isObject ? objectConstructor : iterableConstructor ); - const grouped = col.groupBy((v) => v); + const grouped = col.groupBy((v: unknown) => v); // all groupBy should be instance of Map expect(grouped).toBeInstanceOf(Map); diff --git a/__tests__/hash.ts b/__tests__/hash.ts index bc7b303038..a5dfb9afee 100644 --- a/__tests__/hash.ts +++ b/__tests__/hash.ts @@ -44,10 +44,14 @@ describe('hash', () => { const genValue = gen.oneOf([gen.string, gen.int]); - check.it('generates unsigned 31-bit integers', [genValue], (value) => { - const hashVal = hash(value); - expect(Number.isInteger(hashVal)).toBe(true); - expect(hashVal).toBeGreaterThan(-(2 ** 31)); - expect(hashVal).toBeLessThan(2 ** 31); - }); + check.it( + 'generates unsigned 31-bit integers', + [genValue], + (value: Array) => { + const hashVal = hash(value); + expect(Number.isInteger(hashVal)).toBe(true); + expect(hashVal).toBeGreaterThan(-(2 ** 31)); + expect(hashVal).toBeLessThan(2 ** 31); + } + ); }); diff --git a/__tests__/join.ts b/__tests__/join.ts index 02102de7f3..11cbd1a332 100644 --- a/__tests__/join.ts +++ b/__tests__/join.ts @@ -36,7 +36,7 @@ describe('join', () => { check.it( 'behaves the same as Array.join', [gen.array(gen.primitive), gen.primitive], - (array, joiner) => { + (array: Array, joiner: string) => { expect(Seq(array).join(joiner)).toBe(array.join(joiner)); } ); diff --git a/__tests__/tsconfig.json b/__tests__/tsconfig.json index 4df4b5b796..86b798b440 100644 --- a/__tests__/tsconfig.json +++ b/__tests__/tsconfig.json @@ -1,5 +1,6 @@ { "extends": "../tsconfig.json", + "include": ["./"], "compilerOptions": { // TODO remove those "false" value that make the code less strict "noImplicitAny": false, diff --git a/__tests__/zip.ts b/__tests__/zip.ts index ca32a3f88e..28343eb504 100644 --- a/__tests__/zip.ts +++ b/__tests__/zip.ts @@ -110,7 +110,7 @@ describe('zip', () => { check.it( 'is always the size of the longest sequence', [gen.array(gen.posInt).notEmpty()], - (lengths) => { + (lengths: Array) => { const ranges = lengths.map((l) => Range(0, l)); const first = ranges.shift(); const zipped = first.zipAll.apply(first, ranges);