samchon / tgrid

TypeScript RPC (Remote Procedure Call) for WebSocket and Worker protocols
https://tgrid.com/
MIT License
141 stars 19 forks source link

Compile error on Driver after upgrading the TypeScript to v3.9.2 #34

Closed samchon closed 3 years ago

samchon commented 4 years ago

Summary

After upgrading the TypeScript to v3.9.2, the Driver.Promisive causes a type of compile error like below. The error message is telling that the Driver.Promisive is referencing itself circularly, but such error had not been occurred until the update. TypeScript v3.8.3 does not generate such, recursive reference, compile error.

src/components/Driver.ts:21:101 - error TS2315: Type 'Promisive' is not generic.
src/components/Driver.ts:41:17 - error TS2456: Type alias 'Promisive' circularly references itself.
src/components/Driver.ts:47:22 - error TS2315: Type 'Promisive' is not generic.

Code occuring the bug

https://github.com/samchon/tgrid/blob/85cab6a2995adf5d52320f30c5f7e2109b6a4754/src/components/Driver.ts#L41-L50

Looking at implementation code of the Driver.Promisive type, you can see that the Driver.Promisive is referencing itself in the 47th line. However, generic target of the recursive referencing is not Instance itself but Instance[P], a child instance belonged to the Instance.

Therefore, I deduct that after the upgrade of TypeScript to v3.9.2, TypeScript compiler has lost to distinguishing the target structure's hierarchical relationship when using the recursive referencing type like the Driver.Promisive.

How to do

I'll write a bug reporting issue into the TypeScript repository. Until the TypeScript developers fix the error, we need to use old version of TypeScript when using the TGrid or recursive generic type.

samchon commented 4 years ago

I've fixed the error by shifting the Readonly type wrapper from Driver.Promisive to Driver. Therefore, the error has been fixed. From the tgrid@0.4.3 update, there would not be any error in the typescript@3.9.2 environment.

By the way, there's not any difference between below two codes, but TypeScript v3.9.2 compiler draws different results. I need to study the detailed reason and write an issue to the TypeScript, with much easier sample code than below:

Before Patch - Be Compile Error

The Readonly type is wrapping the Driver.Promisive type from the inside.

export type Driver<Controller extends object, Parametric extends boolean = false> 
    = Driver.Promisive<Controller, Parametric>;

export namespace Driver
{
    export type Promisive<Instance extends object, UseParametric extends boolean = false> = Readonly<
    {
        [P in keyof Instance]: Instance[P] extends Function
            ? Functional<Instance[P], UseParametric> // function, its return type would be capsuled in the Promise
            : value_of<Instance[P]> extends object
                ? Instance[P] extends object
                   ? Promisive<Instance[P], UseParametric> // object would be promisified
                   : never // cannot be
                : never // atomic value
    } & IRemoteObject>;
}

After Patch - No Error

The Readonly type is wrapping Driver.Promisive type from the outside by the Driver type.

export type Driver<Controller extends object, Parametric extends boolean = false> 
    = Readonly<Driver.Promisive<Controller, Parametric>>;

export namespace Driver
{
    export type Promisive<Instance extends object, UseParametric extends boolean = false> = 
    {
        [P in keyof Instance]: Instance[P] extends Function
            ? Functional<Instance[P], UseParametric> // function, its return type would be capsuled in the Promise
            : value_of<Instance[P]> extends object
                ? Instance[P] extends object
                   ? Promisive<Instance[P], UseParametric> // object would be promisified
                   : never // cannot be
                : never // atomic value
    };
}