TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Object.isPartOfTypeNode crashes with TypeError: Cannot read properties of undefined (reading 'kind')

Open Beraliv opened this issue 3 years ago • 6 comments

Bug Report

🔎 Search Terms

Object.isPartOfTypeNode and TypeError: Cannot read properties of undefined

🕗 Version & Regression Information

  • This is a crash
  • This is the behaviour in every version I tried (4.7.3, 4.7.4, next and nightly which was 4.8.0-dev.20220804 for me), and I reviewed the FAQ for entries about tuple, recursion, tail, elimitation, depth and limitation
  • I was unable to test this on prior versions because I use 4.7.3 in my project

⏯ Playground Link

Playground link with relevant code

💻 Code

I reduced the codebase of ttuple to 64 lines.

type AnyArray = readonly any[];

type DigitMapping<T> = {
  "0": [];
  "1": [T];
  "2": [T, T];
  "3": [T, T, T];
  "4": [T, T, T, T];
  "5": [T, T, T, T, T];
  "6": [T, T, T, T, T, T];
  "7": [T, T, T, T, T, T, T];
  "8": [T, T, T, T, T, T, T, T];
  "9": [T, T, T, T, T, T, T, T, T];
};

type Multiply10<T extends AnyArray> = [
  ...T,
  ...T,
  ...T,
  ...T,
  ...T,
  ...T,
  ...T,
  ...T,
  ...T,
  ...T
];

type Add<N1 extends AnyArray, N2 extends AnyArray> = [...N1, ...N2];

type _ToTuple<
  V,
  S extends string,
  T extends AnyArray = []
> = S extends `${infer D}${infer Rest}`
  ? _ToTuple<
      V,
      Rest,
      Add<Multiply10<T>, DigitMapping<V>[D & keyof DigitMapping<V>]>
    >
  : [...T, ...V[], ...T];

type ToTuple<V, S extends string> = _ToTuple<V, S>;

type ElementOf<T extends AnyArray> = T extends readonly (infer V)[] ? V : never;

const length = <
  T extends AnyArray,
  S extends `${number}`,
  R = ToTuple<ElementOf<T>, S>
>(
  array: T,
  condition: `>= ${S}`
): array is R extends T ? R : never => {
  const expectedLength = Number(condition.split(" ")[1]);

  if (array.length >= expectedLength) {
    return true;
  }

  return false;
};

export { length };

Also the code is available in the branch here – https://github.com/Beraliv/ttuple/pull/22

🙁 Actual behaviour

➜ npm run build

> [email protected] build
> tsc --project tsconfig.json

/Users/beraliv/Documents/Code/ttuple/node_modules/typescript/lib/tsc.js:96887
                throw e;
                ^

TypeError: Cannot read properties of undefined (reading 'kind')
    at Object.isPartOfTypeNode (/Users/beraliv/Documents/Code/ttuple/node_modules/typescript/lib/tsc.js:11787:25)
    at _loop_15 (/Users/beraliv/Documents/Code/ttuple/node_modules/typescript/lib/tsc.js:50429:51)
    at createNormalizedTupleType (/Users/beraliv/Documents/Code/ttuple/node_modules/typescript/lib/tsc.js:50445:31)
    at createNormalizedTypeReference (/Users/beraliv/Documents/Code/ttuple/node_modules/typescript/lib/tsc.js:50398:45)
    at instantiateTypeWorker (/Users/beraliv/Documents/Code/ttuple/node_modules/typescript/lib/tsc.js:52755:77)
    at instantiateTypeWithAlias (/Users/beraliv/Documents/Code/ttuple/node_modules/typescript/lib/tsc.js:52740:26)
    at instantiateType (/Users/beraliv/Documents/Code/ttuple/node_modules/typescript/lib/tsc.js:52726:37)
    at getMappedType (/Users/beraliv/Documents/Code/ttuple/node_modules/typescript/lib/tsc.js:52449:63)
    at /Users/beraliv/Documents/Code/ttuple/node_modules/typescript/lib/tsc.js:52709:92
    at Object.map (/Users/beraliv/Documents/Code/ttuple/node_modules/typescript/lib/tsc.js:367:29)

🙂 Expected behaviour

➜ npm run build

> [email protected] build
> tsc --project tsconfig.json

If I replace ToTuple with _ToTuple, it starts working 🤯

As I've seen example with GetChar in release notes of TS 4.5, it should be fine to declare it this way – https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#tailrec-conditional

ℹ️ Additional information

I connected the project to node debugger and could see that in _loop_15 9th element was in the branch of tuple type (after check of isTupleType), but the length of elements.length + expandedTypes.length is 11100 (not sure what it means) so it tried to throw an error, but currentNode was undefined

Beraliv avatar Aug 04 '22 22:08 Beraliv

A shorter repro, if possible, would be greatly appreciated if you have some spare time. Thanks!

RyanCavanaugh avatar Aug 04 '22 22:08 RyanCavanaugh

A shorter repro, if possible, would be greatly appreciated if you have some spare time. Thanks!

Not sure if it's possible, but will try to do it this weekend

Beraliv avatar Aug 05 '22 08:08 Beraliv

I found out 2 interesting things:

  1. If I replace ToTuple with _ToTuple, it starts working 🤯
  2. If I move ToTuple to the file with length, it also starts working

So it should be important that:

  1. ToTuple is located in a different file
  2. There are 2 generic types _ToTuple (with tail recursion elimination) and ToTuple

I moved all the minimal changes where it's still not working for me to this repo – https://github.com/Beraliv/ttuple-object-isPartOfTypeNode-cannot-read-kind

I will try to reduce the test case, but that's what I came up with at the moment

Beraliv avatar Aug 05 '22 08:08 Beraliv

Here's a simplified repo in 4.7.4 workbench. You can see the error in the devtools console.

// @filename: index.ts
import { ToTuple } from "./helper";

export const fn = function<S extends string>(foo: ToTuple<any, S>): void {
   
}
 
// @filename: helper.ts
type _ToTuple<
  V,
  S extends string,
  T extends any[]
> = S extends `${infer H}${infer Rest}`
  ? _ToTuple<
      V,
      Rest,
      [...[
        ...T,
        ...T,
        ...T,
        ...T,
        ...T,
        ...T,
        ...T,
        ...T,
        ...T,
      ], 0]
    >
  : never; 

export type ToTuple<V, S extends string> = _ToTuple<V, S, []>;

The behavior is quite weird. And here is some ways I found to make the error disappear.

  • Merge the two files into a single, as @Beraliv mentioned in comment.
  • Do not export fn.
  • Use function declaration for fn, not function expression.
  • Export _ToTuple, even it's not imported anywhere.
  • Reduce the times of repeated ...T, to 3.
  • Remove the element 0 following the repeated ...T,.
  • Remove the first unused type parameter V in _ToTuple.

whzx5byb avatar Aug 05 '22 12:08 whzx5byb

Thank you @whzx5byb for simplification!

  • Merge the two files into a single, as @Beraliv mentioned in comment.

❌ As I have tests in the original library, it's not possible at the moment

  • Do not export fn.

❌ This function is used as public API, that's also not possible at the moment

  • Use function declaration for fn, not function expression.

✅ ~Yeah, I also tried it and it worked.~ If I use declare const length, it will work. Function overloads are also working for me

  • Export _ToTuple, even it's not imported anywhere.

✅ Yeah, at the moment I only export ToTuple and use it, replacing it with _ToTuple make it work at the moment

  • Reduce the times of repeated ...T, to 3.

❌ Unfortunately, that's the only way to align numbers in string literal types with tuples. That's used in tuple validation and won't be changed (at least unless there's another way to transform '5' to [number, number, number, number, number])

  • Remove the element 0 following the repeated ...T,

❌ The logic behind adding 0 looks a little bit more complicated than it, I cannot simply remove it at the moment, because it's a basement of the whole functionality I use for the library (same as previous point with ...T)


So there are ways to make it work so it's a non-blocker for me.

Is there anything I can help you with to make this behaviour work? I can also contribute if you don't mind. But I'm still new to the codebase and might need help

Beraliv avatar Aug 05 '22 12:08 Beraliv

@andrewbranch hey 👋

do you need any help with the issue?

I wanted to contribute at some point, but want to understand the way it's usually done so we will be aligned and don't waste time on the unnecessary changes

Thank you in advance!

Beraliv avatar Aug 09 '22 15:08 Beraliv

You are welcome to give it a try by following the process in https://github.com/microsoft/TypeScript/blob/main/CONTRIBUTING.md, but I have no idea how challenging it will be, and we may not be able to give you much support if you get stuck—if you end up solving it I’ll merge it, but if it seems like it will be quicker for me to just start fresh, that’s what I’ll do. That’s in contrast to “Help Wanted” and “Good First Issue” issues, where I try to offer more guidance. So you might want to look for one of those if you just want to contribute in general, but if you’re set on this issue, feel free, but at your own risk 🙂

andrewbranch avatar Aug 15 '22 22:08 andrewbranch

You are welcome to give it a try by following the process in https://github.com/microsoft/TypeScript/blob/main/CONTRIBUTING.md, but I have no idea how challenging it will be, and we may not be able to give you much support if you get stuck—if you end up solving it I’ll merge it, but if it seems like it will be quicker for me to just start fresh, that’s what I’ll do. That’s in contrast to “Help Wanted” and “Good First Issue” issues, where I try to offer more guidance. So you might want to look for one of those if you just want to contribute in general, but if you’re set on this issue, feel free, but at your own risk 🙂

It sounds reasonable

I will start from “Help Wanted” and “Good First Issue” first, then will jump on this one, if it's working for you

Beraliv avatar Aug 24 '22 14:08 Beraliv

This crash appears to have been fixed already. @typescript-bot will tell us what the fix was.

andrewbranch avatar Apr 06 '23 17:04 andrewbranch

For some reason the crash isn’t reproducing in the repro runner, but it was fixed between 4.9 and 5.0.

andrewbranch avatar Apr 06 '23 18:04 andrewbranch

The change between v4.9.5 and v5.0.3 occurred at 0e198c2c1d33eb97653ff51ce71e97683e22b1ed.

typescript-bot avatar Apr 06 '23 19:04 typescript-bot