Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] number[] not assignable to ConcatArray<number> #32

Open
AnyhowStep opened this issue Jul 24, 2019 · 4 comments
Open

[Bug] number[] not assignable to ConcatArray<number> #32

AnyhowStep opened this issue Jul 24, 2019 · 4 comments

Comments

@AnyhowStep
Copy link

declare const src : number[];
declare function foo (dst : ConcatArray<number>) : void;
//This is allowed by TS
foo(src);

According to TS, number[] is assignable to ConcatArray<number>.

But ts-simple-type does not think so.

@AnyhowStep
Copy link
Author

Actually, let me investigate this further.

@AnyhowStep
Copy link
Author

I was experiencing other suspicious problems with this library and re-installed. It fixed those suspicious problems but this one remained.

@AnyhowStep AnyhowStep reopened this Jul 24, 2019
@runem
Copy link
Owner

runem commented Jul 24, 2019

Thanks for this issue! First of all, I'm sorry that you are experiencing problems with ts-simple-type, I'll try to fix them as quickly as possible. I suspect the problems that you experienced before can be because of two different version of Typescript in your node_modules, because it will result in strange behavior due to incompatible TypeFlags. If you encounter strange problems again, I export an undocumented function called setTypescriptModule that can set a specific Typescript module for this library to use.

Regarding your problems with ConcatArray, this actually taps into the biggest shortcoming in ts-simple-type as of now (I have been thinking a lot on how to handle it). Basically the problem can be boiled down to balancing "ease of use" and "correctness". Let me explain.

Requirement 1: First of all, an array can be represent with different types: ReadonlyArray<number>, ConcatArray<number>, Array<number>, number[] (this is the same as Array<number>) and ArrayLike<number>. Typescript compares the structure of these types when checking assignability, so you can even make your special own array types if you implement all required members of the Array type.

Requirement 2: Secondly, the aim of this library is to provide an easy way to work with Typescript types. Therefore you should be able easily construct highly used types like Array<number> like this: {kind: SimpleTypeKind.ARRAY, type: {kind: SimpleTypeKind.NUMBER}} (this also increases the speed of comparing types). If I didn't make SimpleTypeKind.ARRAY, you would need to create the type like this by hand:

const myArray = { 
  kind: 'GENERIC_ARGUMENTS',
  typeArguments: [ { kind: 'NUMBER' } ] ,
  target: { 
     kind: 'OBJECT',
     name: 'Array',
     typeParameters: [ { kind: 'GENERIC_PARAMETER', name: 'T' } ],
     members: [ 
         { name: 'length', optional: false, type: { kind: 'NUMBER' } },
         { name: 'slice',
          optional: false,
          type:
           { kind: 'FUNCTION',
             returnType:
              { kind: 'ARRAY',
                type: { kind: 'GENERIC_PARAMETER', name: 'T' },
                name: 'Array' },
             argTypes:
              [ { name: 'start',
                  optional: true,
                  type: { kind: 'NUMBER' },
                  spread: false,
                  initializer: false },
                { name: 'end',
                  optional: true,
                  type: { kind: 'NUMBER' },
                  spread: false,
                  initializer: false } ] } } ],
     
       .........
       .........
       .........

     ]
  }
}

However less used types like ConcatArray<T> aren't parsed into SimpleTypeKind.ARRAY but into the large object shown above.

Requirement 3: Thirdly, when comparing Typescript types, I first transform them to SimpleType and then I compare them. This means that you can compare Typescript types against your own hand made SimpleTypes. It even means that you can compare two SimpleTypes without the need for a TypeChecker, for example in the browser!

The Problem: For requirement 2, I parse highly used types like Array<T> into SimpleTypeKind.ARRAY, but sadly I lose the structure of the Array<T> type in the process. The problem is that when I'm checking assignability I can end up comparing a SimpleTypeKind.ARRAY with the entire parsed type of ConcatArray<T> taken directly from lib.d.ts, and this will result in ts-simple-type telling that they are not assignable (just like you are experiencing). I would be able to solve it easly if I had access to the Typescript program in the comparison step, but due to requirement 2, I want this library to work without a Typescript program in that phase.

Solution: I have been thinking a lot on how to handle it. I don't want to build a half-baked, hard-coded solution, but I still want to include all 3 requirements. I also don't want to make a SimpleTypeKind for each lib type. I think the following is the solution that I'm going to make:

  • When building this library, I should parse and generate snapshots of highly used types like Array, Promise and Date and ship them together with the library. Then, when I have to compare SimpleTypeKind.ARRAY against another type, I would be able to instead compare structurally because I would have access to the entire structure of the array type. The only shortcoming I can see with this solution is that I end up baking a specific version of lib.d.ts into the shipped library.

This ended up a bit long and technical, but I hope you understand my thoughts and concerns. I'll keep you updated on the progress in this issue 👍

@AnyhowStep
Copy link
Author

I actually appreciate that you went long and technical.

I understand that type checking is a beast, even more so with structural type systems!
And even way more so when there are rules involved that aren't even documented!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants