Hur hittar man orsaken till ett ounderligt TypeScript-kompileringsfel?


Jag får ett märkligt kompileringsfel. Det anger: RangeError: Value undefined out of range for undefined options property undefined.

Min känsla hittills är att kompilatorn internt kör in i en loop och fyller upp en Map tills den är full. Min bästa gissning är att detta är kopplat till någon felaktig typdeklaration i vår egen kodbas.

Mitt problem är att kompilatorn inte säger vilken del av min kodbas som är orsaken till detta problem och det hände efter en paketuppdatering. Så jag ser inga ledtrådar om vilken specifik del av vår kodbas som är roten till detta. Hur kan jag övertala TypeScript att tala om detta för mig?

Hela stackspåret ser ut så här:

yarn tsc
yarn run v1.22.4
/myProject/app/node_modules/.bin/tsc
/myProject/app/node_modules/typescript/lib/tsc.js:90679
                throw e;
                ^RangeError: Value undefined out of range for undefined options property undefined
    at Map.set (<anonymous>)
    at recursiveTypeRelatedTo (/myProject/app/node_modules/typescript/lib/tsc.js:50962:30)
    at isRelatedTo (/myProject/app/node_modules/typescript/lib/tsc.js:50543:34)
    at checkTypeRelatedTo (/myProject/app/node_modules/typescript/lib/tsc.js:50229:26)
    at isTypeRelatedTo (/myProject/app/node_modules/typescript/lib/tsc.js:50192:24)
    at isTypeSubtypeOf (/myProject/app/node_modules/typescript/lib/tsc.js:49480:20)
    at /myProject/app/node_modules/typescript/lib/tsc.js:47289:90
    at Object.some (/myProject/app/node_modules/typescript/lib/tsc.js:658:25)
    at _loop_14 (/myProject/app/node_modules/typescript/lib/tsc.js:47289:45)
    at removeStringLiteralsMatchedByTemplateLiterals (/myProject/app/node_modules/typescript/lib/tsc.js:47294:21)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Bakgrund

Detta hände efter att jag uppgraderade react-hook-form från version 6 till 7, utan några andra ändringar i kodbasen.

Jag har redan försökt följande (allt med samma resultat):

  • Uppdaterar TypeScript till den nyaste 4.3.X-versionen
  • Uppdaterar till react-hook-form 7.0.0 (istället för den senaste)
  • Det går att reproducera på en annan dator
  • Raderade node_modules
  • Kör tsc -b --verbose

Sidoanteckningar

  • Kompileringen tar lång tid och använder mycket minne innan det felmeddelandet visas.
  • När jag startar projektet i utvecklingsläge startar det faktiskt och visar webbplatsen ett ögonblick, men sedan byter det till samma felmeddelande.

Svar #1

Jag hade också exakt samma fel när jag körde tsc (både på snowpack och fristående).

I mitt fall orsakades det av "Cirkulärt beroende"-problemet.

Jag använde indexed access type i en specifik del av den nyligen tillagda koden, och filen där objekttypen är definierad och filen där egenskapstypen är definierad är separerade och refererade.

Så jag ändrade koden som använde indexerad åtkomsttyp till den faktiska egenskapstypen.

Så felet uppstår inte längre.

Svar #2

Felet är ganska beskrivande (eller är det inte)? Det ser ut som att du har (eller biblioteket som du använder) någon form av oändlig loop någonstans.

Map kan lagra upp till 16777216 (2^24) värden, efter att du har lagrat denna mängd och försöker lägga till 1 till kommer du att få detta konstiga RangeError.

Här är ett exempel på hur du kan återskapa detta fel (vänta omkring 10s):

const testMap = new Map()

Array.from(
  { length: Math.pow(2, 24) },
  (_, i) => testMap.set(i, 'x')
)

console.log(testMap.get(16777215)) // last value, no error
testMap.set(Math.pow(2, 24) + 1, 'x') // error will occur

Det är svårt att säga hur man löser ditt exakta problem utan din hela kod, men jag skulle göra något liknande detta:

  1. Hitta alla Map-deklarationer och kommentera dem,
  2. (valfritt) fel bör försvinna, appen kan sluta fungera,
  3. Avkommentera Map-deklarationer en efter en och kontrollera efter vilken du får RangeError.

Om felet inte försvinner efter detta är det förmodligen fallet med ett av de bibliotek som du nyligen uppdaterade. I så fall kan det enda sättet att lösa detta vara att återställa projektet till den senaste fungerande versionen och tillämpa ändringarna steg för steg samtidigt som du tittar på resultatet.

Dessutom

Vad som är ännu mer intressant är att om du behandlar standard Object som en "Map" kan du lagra upp till 2^32 - 1 värden (Array.length).

Här är ett exempel på hur man återskapar detta fel (vänta cirka 10s, kan krascha tidigare, beror på RAM och Webbläsare):

const testObj = {}

Array.from(
  { length: Math.pow(2, 32) - 1 },
  (_, i) => testObj[i] = i
)

console.log(testObj[Math.pow(2, 32) - 1]) // last value, no error
testObj[Math.pow(2, 32)] // RangeError: Invalid array length

Alternativt exempel på ovanstående:

Array.from({ length: Math.pow(2, 32) }) // RangeError