microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.26k stars 12.52k forks source link

TypeError: Cannot read properties of undefined (reading 'length') at elaborateDidYouMeanToCallOrConstruct #60278

Open staab opened 1 month ago

staab commented 1 month ago

🔎 Search Terms

undefined length elaborateDidYouMeanToCallOrConstruct

🕗 Version & Regression Information

npm warn ERESOLVE overriding peer dependency
npm warn While resolving: coracle@0.4.14
npm warn Found: typescript@5.7.0-dev.20241018
npm warn node_modules/typescript
npm warn   typescript@"5.7.0-dev.20241018" from the root project
npm warn
npm warn Could not resolve dependency:
npm warn peerOptional typescript@">=5.0.0" from nostr-tools@2.8.1
npm warn node_modules/nostr-tools
npm warn   nostr-tools@"^2.8.1" from the root project
npm warn   4 more (@welshman/content, @welshman/dvm, @welshman/signer, @welshman/util)

⏯ Playground Link

No response

💻 Code

I'm not able to isolate the problem because the compiler is crashing without any information about my source files. You can clone the project from https://github.com/coracle-social/coracle and reproduce simply by running git checkout 5e70d4ed499b6721f41318644b6250713085c923; npm i; npx tsc.

🙁 Actual behavior

Running npx tsc in my project gives me:


/Users/me/nostr/coracle/node_modules/typescript/lib/tsc.js:120987
      throw e;
      ^

TypeError: Cannot read properties of undefined (reading 'length')
    at elaborateDidYouMeanToCallOrConstruct (/Users/me/nostr/coracle/node_modules/typescript/lib/tsc.js:62406:62)
    at elaborateError (/Users/me/nostr/coracle/node_modules/typescript/lib/tsc.js:62360:10)
    at checkTypeRelatedToAndOptionallyElaborate (/Users/me/nostr/coracle/node_modules/typescript/lib/tsc.js:62344:24)
    at getSignatureApplicabilityError (/Users/me/nostr/coracle/node_modules/typescript/lib/tsc.js:74383:14)
    at resolveCall (/Users/me/nostr/coracle/node_modules/typescript/lib/tsc.js:74779:25)
    at resolveCallExpression (/Users/me/nostr/coracle/node_modules/typescript/lib/tsc.js:75194:12)
    at resolveSignature (/Users/me/nostr/coracle/node_modules/typescript/lib/tsc.js:75587:16)
    at getResolvedSignature (/Users/me/nostr/coracle/node_modules/typescript/lib/tsc.js:75613:18)
    at checkCallExpression (/Users/me/nostr/coracle/node_modules/typescript/lib/tsc.js:75724:23)
    at checkExpressionWorker (/Users/me/nostr/coracle/node_modules/typescript/lib/tsc.js:79133:16)

Node.js v20.18.0

On my Debian 11 VPS, I get a similar error:


/home/me/node_modules/typescript/lib/tsc.js:120986
      throw e;
      ^

TypeError: Cannot read properties of undefined (reading 'length')
    at elaborateDidYouMeanToCallOrConstruct (/home/me/node_modules/typescript/lib/tsc.js:62405:62)
    at elaborateError (/home/me/node_modules/typescript/lib/tsc.js:62360:10)
    at checkTypeRelatedToAndOptionallyElaborate (/home/me/node_modules/typescript/lib/tsc.js:62344:24)
    at getSignatureApplicabilityError (/home/me/node_modules/typescript/lib/tsc.js:74382:14)
    at resolveCall (/home/me/node_modules/typescript/lib/tsc.js:74778:25)
    at resolveCallExpression (/home/me/node_modules/typescript/lib/tsc.js:75193:12)
    at resolveSignature (/home/me/node_modules/typescript/lib/tsc.js:75586:16)
    at getResolvedSignature (/home/me/node_modules/typescript/lib/tsc.js:75612:18)
    at checkCallExpression (/home/me/node_modules/typescript/lib/tsc.js:75723:23)
    at checkExpressionWorker (/home/me/node_modules/typescript/lib/tsc.js:79132:16)

Node.js v18.20.4

🙂 Expected behavior

I expect typescript to not crash.

Additional information about the issue

I completely re-installed nvm/npm/node, removed all node_modules folders on my system, removed the project director and re-cloned, just to make sure my environment wasn't dirty somehow.

Andarist commented 1 month ago

I don't have the energy right now to minimize this Ramda madness further. This is what I got so far:

Repro ```ts declare type Cast = A1 extends A2 ? A1 : A2; declare type Key = string | number | symbol; declare type BuiltIn = Function | Error | Date | { readonly [Symbol.toStringTag]: string; } | RegExp | Generator; declare type Extends = [ A1 ] extends [never] ? 0 : A1 extends A2 ? 1 : 0; declare type Has = [ U1 ] extends [U] ? 1 : 0; declare type Anyfy = { [K in keyof O]: any; }; declare type _OptionalKeys = { [K in keyof O]-?: {} extends Pick ? K : never; }[keyof O]; declare type At = A extends List ? number extends A['length'] ? K extends number | `${number}` ? A[never] | undefined : undefined : K extends keyof A ? A[K] : undefined : unknown extends A ? unknown : K extends keyof A ? A[K] : undefined; declare type List = ReadonlyArray; declare type Length = L['length']; declare type MergeProp = K extends OOKeys ? Exclude | O1K : [OK] extends [never] ? O1K : OK extends fill ? O1K : OK; declare type _RequiredKeys = { [K in keyof O]-?: {} extends Pick ? never : K; }[keyof O]; declare type ORequiredKeys = O extends unknown ? _RequiredKeys : never; declare type __Pick = { [P in K]: O[P]; } & {}; declare type _Pick = __Pick; declare type _Omit = _Pick>; declare type ObjectOf = O extends unknown ? number extends Length ? _Pick : _Omit : never; declare type RequiredKeys = ORequiredKeys>; declare type Longer = L extends unknown ? L1 extends unknown ? { 0: 0; 1: 1; }[Has, RequiredKeys>] : never : never; declare type Depth = 'flat' | 'deep'; declare type MergeFlatList> = number extends Length ? MergeFlatChoice[] : Longer extends 1 ? { [K in keyof L]: MergeProp, fill, LOK, K>; } : { [K in keyof L1]: MergeProp, L1[K], fill, LOK, K>; }; type MergeFlatObject> = { [K in keyof (Anyfy & O1)]: MergeProp, At, fill, OOKeys, K>; } & {}; declare type MergeFlatChoice = O extends ignore ? O : O1 extends ignore ? O : O extends List ? O1 extends List ? MergeFlatList : MergeFlatObject : MergeFlatObject; declare type MergeFlat = O extends unknown ? O1 extends unknown ? MergeFlatChoice : never : never; declare type MergeDeepList = number extends Length ? MergeDeepChoice[] : Longer extends 1 ? { [K in keyof L]: MergeDeepChoice, ignore, fill, _OptionalKeys, K>; } : { [K in keyof L1]: MergeDeepChoice, L1[K], ignore, fill, _OptionalKeys, K>; }; declare type MergeDeepObject> = { [K in keyof (Anyfy & O1)]: MergeDeepChoice, At, ignore, fill, OOKeys, K>; }; declare type MergeDeepChoice = [ OK ] extends [never] ? MergeProp : [ O1K ] extends [never] ? MergeProp : OK extends ignore ? MergeProp : O1K extends ignore ? MergeProp : OK extends List ? O1K extends List ? MergeDeepList : MergeProp : OK extends object ? O1K extends object ? MergeDeepObject : MergeProp : MergeProp; declare type MergeDeep = O extends unknown ? O1 extends unknown ? MergeDeepChoice : never : never; declare type Merge = { 'flat': MergeFlat; 'deep': MergeDeep; }[depth]; declare type __Assign, depth extends Depth, ignore extends object, fill extends any, I extends Iteration = IterationOf<0>> = { 0: __Assign], O, depth, ignore, fill>, Os, depth, ignore, fill, Next>; 1: O; }[Extends, Length>]; declare type Next = IterationMap[I[3]]; declare type IterationOf = `${N}` extends keyof IterationMap ? IterationMap[`${N}`] : IterationMap['__']; declare type IterationMap = { '__': [number, '-' | '0' | '+', '__', '__', '__']; '-100': [-100, '-', '__', '-99', '100']; '-99': [-99, '-', '-100', '-98', '99']; '-98': [-98, '-', '-99', '-97', '98']; '-97': [-97, '-', '-98', '-96', '97']; '-96': [-96, '-', '-97', '-95', '96']; '-95': [-95, '-', '-96', '-94', '95']; '-94': [-94, '-', '-95', '-93', '94']; '-93': [-93, '-', '-94', '-92', '93']; '-92': [-92, '-', '-93', '-91', '92']; '-91': [-91, '-', '-92', '-90', '91']; '-90': [-90, '-', '-91', '-89', '90']; '-89': [-89, '-', '-90', '-88', '89']; '-88': [-88, '-', '-89', '-87', '88']; '-87': [-87, '-', '-88', '-86', '87']; '-86': [-86, '-', '-87', '-85', '86']; '-85': [-85, '-', '-86', '-84', '85']; '-84': [-84, '-', '-85', '-83', '84']; '-83': [-83, '-', '-84', '-82', '83']; '-82': [-82, '-', '-83', '-81', '82']; '-81': [-81, '-', '-82', '-80', '81']; '-80': [-80, '-', '-81', '-79', '80']; '-79': [-79, '-', '-80', '-78', '79']; '-78': [-78, '-', '-79', '-77', '78']; '-77': [-77, '-', '-78', '-76', '77']; '-76': [-76, '-', '-77', '-75', '76']; '-75': [-75, '-', '-76', '-74', '75']; '-74': [-74, '-', '-75', '-73', '74']; '-73': [-73, '-', '-74', '-72', '73']; '-72': [-72, '-', '-73', '-71', '72']; '-71': [-71, '-', '-72', '-70', '71']; '-70': [-70, '-', '-71', '-69', '70']; '-69': [-69, '-', '-70', '-68', '69']; '-68': [-68, '-', '-69', '-67', '68']; '-67': [-67, '-', '-68', '-66', '67']; '-66': [-66, '-', '-67', '-65', '66']; '-65': [-65, '-', '-66', '-64', '65']; '-64': [-64, '-', '-65', '-63', '64']; '-63': [-63, '-', '-64', '-62', '63']; '-62': [-62, '-', '-63', '-61', '62']; '-61': [-61, '-', '-62', '-60', '61']; '-60': [-60, '-', '-61', '-59', '60']; '-59': [-59, '-', '-60', '-58', '59']; '-58': [-58, '-', '-59', '-57', '58']; '-57': [-57, '-', '-58', '-56', '57']; '-56': [-56, '-', '-57', '-55', '56']; '-55': [-55, '-', '-56', '-54', '55']; '-54': [-54, '-', '-55', '-53', '54']; '-53': [-53, '-', '-54', '-52', '53']; '-52': [-52, '-', '-53', '-51', '52']; '-51': [-51, '-', '-52', '-50', '51']; '-50': [-50, '-', '-51', '-49', '50']; '-49': [-49, '-', '-50', '-48', '49']; '-48': [-48, '-', '-49', '-47', '48']; '-47': [-47, '-', '-48', '-46', '47']; '-46': [-46, '-', '-47', '-45', '46']; '-45': [-45, '-', '-46', '-44', '45']; '-44': [-44, '-', '-45', '-43', '44']; '-43': [-43, '-', '-44', '-42', '43']; '-42': [-42, '-', '-43', '-41', '42']; '-41': [-41, '-', '-42', '-40', '41']; '-40': [-40, '-', '-41', '-39', '40']; '-39': [-39, '-', '-40', '-38', '39']; '-38': [-38, '-', '-39', '-37', '38']; '-37': [-37, '-', '-38', '-36', '37']; '-36': [-36, '-', '-37', '-35', '36']; '-35': [-35, '-', '-36', '-34', '35']; '-34': [-34, '-', '-35', '-33', '34']; '-33': [-33, '-', '-34', '-32', '33']; '-32': [-32, '-', '-33', '-31', '32']; '-31': [-31, '-', '-32', '-30', '31']; '-30': [-30, '-', '-31', '-29', '30']; '-29': [-29, '-', '-30', '-28', '29']; '-28': [-28, '-', '-29', '-27', '28']; '-27': [-27, '-', '-28', '-26', '27']; '-26': [-26, '-', '-27', '-25', '26']; '-25': [-25, '-', '-26', '-24', '25']; '-24': [-24, '-', '-25', '-23', '24']; '-23': [-23, '-', '-24', '-22', '23']; '-22': [-22, '-', '-23', '-21', '22']; '-21': [-21, '-', '-22', '-20', '21']; '-20': [-20, '-', '-21', '-19', '20']; '-19': [-19, '-', '-20', '-18', '19']; '-18': [-18, '-', '-19', '-17', '18']; '-17': [-17, '-', '-18', '-16', '17']; '-16': [-16, '-', '-17', '-15', '16']; '-15': [-15, '-', '-16', '-14', '15']; '-14': [-14, '-', '-15', '-13', '14']; '-13': [-13, '-', '-14', '-12', '13']; '-12': [-12, '-', '-13', '-11', '12']; '-11': [-11, '-', '-12', '-10', '11']; '-10': [-10, '-', '-11', '-9', '10']; '-9': [-9, '-', '-10', '-8', '9']; '-8': [-8, '-', '-9', '-7', '8']; '-7': [-7, '-', '-8', '-6', '7']; '-6': [-6, '-', '-7', '-5', '6']; '-5': [-5, '-', '-6', '-4', '5']; '-4': [-4, '-', '-5', '-3', '4']; '-3': [-3, '-', '-4', '-2', '3']; '-2': [-2, '-', '-3', '-1', '2']; '-1': [-1, '-', '-2', '0', '1']; '0': [0, '0', '-1', '1', '0']; '1': [1, '+', '0', '2', '-1']; '2': [2, '+', '1', '3', '-2']; '3': [3, '+', '2', '4', '-3']; '4': [4, '+', '3', '5', '-4']; '5': [5, '+', '4', '6', '-5']; '6': [6, '+', '5', '7', '-6']; '7': [7, '+', '6', '8', '-7']; '8': [8, '+', '7', '9', '-8']; '9': [9, '+', '8', '10', '-9']; '10': [10, '+', '9', '11', '-10']; '11': [11, '+', '10', '12', '-11']; '12': [12, '+', '11', '13', '-12']; '13': [13, '+', '12', '14', '-13']; '14': [14, '+', '13', '15', '-14']; '15': [15, '+', '14', '16', '-15']; '16': [16, '+', '15', '17', '-16']; '17': [17, '+', '16', '18', '-17']; '18': [18, '+', '17', '19', '-18']; '19': [19, '+', '18', '20', '-19']; '20': [20, '+', '19', '21', '-20']; '21': [21, '+', '20', '22', '-21']; '22': [22, '+', '21', '23', '-22']; '23': [23, '+', '22', '24', '-23']; '24': [24, '+', '23', '25', '-24']; '25': [25, '+', '24', '26', '-25']; '26': [26, '+', '25', '27', '-26']; '27': [27, '+', '26', '28', '-27']; '28': [28, '+', '27', '29', '-28']; '29': [29, '+', '28', '30', '-29']; '30': [30, '+', '29', '31', '-30']; '31': [31, '+', '30', '32', '-31']; '32': [32, '+', '31', '33', '-32']; '33': [33, '+', '32', '34', '-33']; '34': [34, '+', '33', '35', '-34']; '35': [35, '+', '34', '36', '-35']; '36': [36, '+', '35', '37', '-36']; '37': [37, '+', '36', '38', '-37']; '38': [38, '+', '37', '39', '-38']; '39': [39, '+', '38', '40', '-39']; '40': [40, '+', '39', '41', '-40']; '41': [41, '+', '40', '42', '-41']; '42': [42, '+', '41', '43', '-42']; '43': [43, '+', '42', '44', '-43']; '44': [44, '+', '43', '45', '-44']; '45': [45, '+', '44', '46', '-45']; '46': [46, '+', '45', '47', '-46']; '47': [47, '+', '46', '48', '-47']; '48': [48, '+', '47', '49', '-48']; '49': [49, '+', '48', '50', '-49']; '50': [50, '+', '49', '51', '-50']; '51': [51, '+', '50', '52', '-51']; '52': [52, '+', '51', '53', '-52']; '53': [53, '+', '52', '54', '-53']; '54': [54, '+', '53', '55', '-54']; '55': [55, '+', '54', '56', '-55']; '56': [56, '+', '55', '57', '-56']; '57': [57, '+', '56', '58', '-57']; '58': [58, '+', '57', '59', '-58']; '59': [59, '+', '58', '60', '-59']; '60': [60, '+', '59', '61', '-60']; '61': [61, '+', '60', '62', '-61']; '62': [62, '+', '61', '63', '-62']; '63': [63, '+', '62', '64', '-63']; '64': [64, '+', '63', '65', '-64']; '65': [65, '+', '64', '66', '-65']; '66': [66, '+', '65', '67', '-66']; '67': [67, '+', '66', '68', '-67']; '68': [68, '+', '67', '69', '-68']; '69': [69, '+', '68', '70', '-69']; '70': [70, '+', '69', '71', '-70']; '71': [71, '+', '70', '72', '-71']; '72': [72, '+', '71', '73', '-72']; '73': [73, '+', '72', '74', '-73']; '74': [74, '+', '73', '75', '-74']; '75': [75, '+', '74', '76', '-75']; '76': [76, '+', '75', '77', '-76']; '77': [77, '+', '76', '78', '-77']; '78': [78, '+', '77', '79', '-78']; '79': [79, '+', '78', '80', '-79']; '80': [80, '+', '79', '81', '-80']; '81': [81, '+', '80', '82', '-81']; '82': [82, '+', '81', '83', '-82']; '83': [83, '+', '82', '84', '-83']; '84': [84, '+', '83', '85', '-84']; '85': [85, '+', '84', '86', '-85']; '86': [86, '+', '85', '87', '-86']; '87': [87, '+', '86', '88', '-87']; '88': [88, '+', '87', '89', '-88']; '89': [89, '+', '88', '90', '-89']; '90': [90, '+', '89', '91', '-90']; '91': [91, '+', '90', '92', '-91']; '92': [92, '+', '91', '93', '-92']; '93': [93, '+', '92', '94', '-93']; '94': [94, '+', '93', '95', '-94']; '95': [95, '+', '94', '96', '-95']; '96': [96, '+', '95', '97', '-96']; '97': [97, '+', '96', '98', '-97']; '98': [98, '+', '97', '99', '-98']; '99': [99, '+', '98', '100', '-99']; '100': [100, '+', '99', '__', '-100']; }; declare type Iteration = [ value: number, sign: '-' | '0' | '+', prev: keyof IterationMap, next: keyof IterationMap, oppo: keyof IterationMap ]; declare type Pos = I[0]; declare type _Assign, depth extends Depth, ignore extends object, fill extends any> = __Assign extends infer X ? Cast : never; declare type Assign, depth extends Depth = 'flat', ignore extends object = BuiltIn, fill extends any = undefined> = O extends unknown ? Os extends unknown ? _Assign : never : never; declare function mergeLeft(l: L): (r: R) => Assign; declare function mergeLeft(l: L, r: R): Assign; function updateIn(k: string, f: (x: T) => T) { return x => ({...x, [k]: f(x[k])}) } type RouterExtensionParams = { path: string queryParams?: Record } class RouterExtension { constructor( readonly router, readonly params: RouterExtensionParams, ) {} clone = params => new RouterExtension(this.router, {...this.params, ...params}) // here cg = config => this.clone(updateIn("config", mergeLeft(config))(this.params)) } ```
staab commented 1 month ago

Amazing, I appreciate that. Ramda is madness, I'm planning to remove it from my project eventually. That gives me an action item, even if it doesn't help with resolving this issue for typescript.

RyanCavanaugh commented 3 weeks ago

We need a (reasonably small) repro

kbrownlees commented 3 weeks ago

We just hit the same issue in our codebase (private). Can confirm the same versions: works fine in 5.5.4 but broken in 5.6. Bit tricky to provide a repro when there are no indication about where the error actually is.

Edit: also broken is @next (5.7.0-dev.20241104)

josh-cloudscape commented 3 weeks ago

@RyanCavanaugh managed to reproduce it

import * as R from "ramda";

const mergeValue = { c: 3 };

const addCToFirstItem = R.adjust(0, R.mergeLeft(mergeValue));

// Should output [{ a: 1, c: 3 }, { b: 2 }]
console.log(addCToFirstItem([{ a: 1 }, { b: 2 }]));

Versions

@types/ramda: 0.30.2
ramda: 0.30.1
typescript: 5.6.3

Seems to be a combination of R.adjust and R.mergeLeft. Only happens when using --strict.

Andarist commented 3 weeks ago

We already have a Ramda-based repro, see even the rolled up one here. The problem is that their types are very complex - for somebody to investigate this issue it has to be reduced further

Harris-Miller commented 3 weeks ago

@Andarist @staab Hi, ramda/types maintainer here.

The code example given by @josh-cloudscape I don't think is the issue.

The code you used to reproduce the issue does run and produce the expected output Image

However, the error you are seeing here is valid from a type perspective: https://tsplay.dev/wjMv7W

The error is very difficult to decipher, and I do wish that was better, but what it's trying to tell you is since it doesn't know yet what the type R.adjust is expecting it can't just merge { c: number } into it.

Even if that wasn't the case you'd have a problem because [{ a: 1 }, { b: 2 }] is infered as

({
    a: number;
    b?: undefined;
} | {
    b: number;
    a?: undefined;
})[]

And doesn't have a c prop. So directly mutating would error: https://tsplay.dev/weqGgw

So the error isn't in Ramda, it's that your types are mismatched. Add some correct types and it works as expected: https://tsplay.dev/WGQLoN

The error around undefined length elaborateDidYouMeanToCallOrConstruct is not directly from types-ramda, but another project ts-toolbelt

R.mergeRight utilizes a type O.Assign from ts-toolbelt

ramda existed long before typescript so a DefinitelyTyped project is where all the types were defined. ts-toolbelt was originally added there. ramda since pulled on those types int the types/ramda to allow us to accelerate typing improvements (and we've come a long way), but we can't just change from using ts-toolbelt without breaking existing userspace. I do admit that ts-toolbelt is very complex, but does simplify how we can type ramda functions in a sane way with expected behaviors in general.

Unfortunately, I cannot say why ts-toolbelt is failing on typescript@5.6