isaacs / node-lru-cache

A fast cache that automatically deletes the least recently used items
http://isaacs.github.io/node-lru-cache/
ISC License
5.35k stars 353 forks source link

Type errors in TypeScript 5.6 due to lib changes (both in source and declaration files) #352

Closed andrewbranch closed 2 months ago

andrewbranch commented 2 months ago

TypeScript 5.6 (currently in RC) includes some changes to builtin iterator types, which causes several of the iterator-returning methods of LRUCache to be unassignable to its implements Map<K, V>. For details, see https://github.com/microsoft/TypeScript/pull/58243. To reproduce:

npm i typescript@rc
npm i @types/node@latest # currently installed @types/node breaks for same reason
tsc --noEmit

src/index.ts:1704:4 - error TS2416: Property 'entries' in type 'LRUCache<K, V, FC>' is not assignable to the same property in base type 'Map<K, V>'.
  Type '() => Generator<[K, V], void, unknown>' is not assignable to type '() => MapIterator<[K, V]>'.
    Call signature return types 'Generator<[K, V], void, unknown>' and 'MapIterator<[K, V]>' are incompatible.
      The types returned by 'next(...)' are incompatible between these types.
        Type 'IteratorResult<[K, V], void>' is not assignable to type 'IteratorResult<[K, V], undefined>'.
          Type 'IteratorReturnResult<void>' is not assignable to type 'IteratorResult<[K, V], undefined>'.
            Type 'IteratorReturnResult<void>' is not assignable to type 'IteratorReturnResult<undefined>'.
              Type 'void' is not assignable to type 'undefined'.

1704   *entries() {
        ~~~~~~~

src/index.ts:1738:4 - error TS2416: Property 'keys' in type 'LRUCache<K, V, FC>' is not assignable to the same property in base type 'Map<K, V>'.
  Type '() => Generator<K, void, unknown>' is not assignable to type '() => MapIterator<K>'.
    Call signature return types 'Generator<K, void, unknown>' and 'MapIterator<K>' are incompatible.
      The types returned by 'next(...)' are incompatible between these types.
        Type 'IteratorResult<K, void>' is not assignable to type 'IteratorResult<K, undefined>'.
          Type 'IteratorReturnResult<void>' is not assignable to type 'IteratorResult<K, undefined>'.
            Type 'IteratorReturnResult<void>' is not assignable to type 'IteratorReturnResult<undefined>'.
              Type 'void' is not assignable to type 'undefined'.

1738   *keys() {
        ~~~~

src/index.ts:1772:4 - error TS2416: Property 'values' in type 'LRUCache<K, V, FC>' is not assignable to the same property in base type 'Map<K, V>'.
  Type '() => Generator<V, void, unknown>' is not assignable to type '() => MapIterator<V>'.
    Call signature return types 'Generator<V, void, unknown>' and 'MapIterator<V>' are incompatible.
      The types returned by 'next(...)' are incompatible between these types.
        Type 'IteratorResult<V, void>' is not assignable to type 'IteratorResult<V, undefined>'.
          Type 'IteratorReturnResult<void>' is not assignable to type 'IteratorResult<V, undefined>'.
            Type 'IteratorReturnResult<void>' is not assignable to type 'IteratorReturnResult<undefined>'.
              Type 'void' is not assignable to type 'undefined'.

1772   *values() {
        ~~~~~~

src/index.ts:1806:3 - error TS2416: Property '[Symbol.iterator]' in type 'LRUCache<K, V, FC>' is not assignable to the same property in base type 'Map<K, V>'.
  Type '() => Generator<[K, V], void, unknown>' is not assignable to type '() => MapIterator<[K, V]>'.
    Call signature return types 'Generator<[K, V], void, unknown>' and 'MapIterator<[K, V]>' are incompatible.
      The types returned by 'next(...)' are incompatible between these types.
        Type 'IteratorResult<[K, V], void>' is not assignable to type 'IteratorResult<[K, V], undefined>'.
          Type 'IteratorReturnResult<void>' is not assignable to type 'IteratorResult<[K, V], undefined>'.
            Type 'IteratorReturnResult<void>' is not assignable to type 'IteratorReturnResult<undefined>'.
              Type 'void' is not assignable to type 'undefined'.

1806   [Symbol.iterator]() {
       ~~~~~~~~~~~~~~~~~

src/index.ts:1848:3 - error TS2416: Property 'forEach' in type 'LRUCache<K, V, FC>' is not assignable to the same property in base type 'Map<K, V>'.
  Type '(fn: (v: V, k: K, self: LRUCache<K, V, FC>) => any, thisp?: any) => void' is not assignable to type '(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any) => void'.
    Types of parameters 'fn' and 'callbackfn' are incompatible.
      Types of parameters 'map' and 'self' are incompatible.
        Type 'LRUCache<K, V, FC>' is not assignable to type 'Map<K, V>'.
          The types returned by 'entries().next(...)' are incompatible between these types.
            Type 'IteratorResult<[K, V], void>' is not assignable to type 'IteratorResult<[K, V], undefined>'.
              Type 'IteratorReturnResult<void>' is not assignable to type 'IteratorResult<[K, V], undefined>'.
                Type 'IteratorReturnResult<void>' is not assignable to type 'IteratorReturnResult<undefined>'.
                  Type 'void' is not assignable to type 'undefined'.

1848   forEach(
       ~~~~~~~

Found 5 errors in the same file, starting at: src/index.ts:1704

As an aside, I noticed that neither npm run build nor npm test seems to type check currently (or at least tshy isn’t reporting the type errors to the console)—is that intended?

isaacs commented 2 months ago

build isn't a defined script name in this package. It uses prepare to build the code, which is the one that npm actually runs when publishing or installing.

isaacs commented 2 months ago

I don't typically worry about TypeScript version changes, especially not rc versions, since I just lock into whatever tshy provides. But in this case, the issue is solved by just dropping the implements Map from the LRUCache class. Looks like TS 5.6 rc doesn't like that it says it implements Map, but the forEach callback function has a thisp: typeof this instead of thisp: Map. 🤷

andrewbranch commented 2 months ago

Yeah, I should have been more clear: this isn’t just a problem for building, this is a problem that all users of lru-cache would see in e.g. node_modules/lru-cache/dist/esm/index.d.ts as soon as they upgrade to TypeScript 5.6 because the problem also exists in your published declaration files. The fix you added looks fine for me though.

build isn't a defined script name in this package. It uses prepare to build the code, which is the one that npm actually runs when publishing or installing.

build is aliased to prepare, which runs tshy, but my point is that I thought that tshy would type check. Do you not type check this package from the CLI or during CI?

isaacs commented 2 months ago

Tshy does type check, but using its own version of typescript that it depends on.