Typescript compiler as a service: how to test if one type is assignable to another?

652 views Asked by At

I'm making a command line nodejs tool that automates renaming symbols in Typescript files, using the Typescript language services.

You tell the tool: rename all symbols of this type to this symbol. Just like resharper, it will also rename local variables, properties, etc. Since it allows renaming multiple symbols at once, you can also swap two symbol names, without needing an intermediate temporary unique name (e.g. rename Foo to Bar and vice vesa).

I had to make the private function getSymbolInfoAtPosition in the language service public to make this work, so that I can get PullSymbol information

Currently it only detects exact name+type matches, by calling getNameAndTypeName on the PullSymbol, but I would like to perform structurally compatible matches.

In C#, this is easy, since a Type has an IsAssignableFrom method.

Does anyone know how the Typescript compiler-as-a-service can be used to detect if one PullSymbol is structurally compatible with another PullSymbol?

Thanks a lot, Peter Verswyvelen

2

There are 2 answers

0
Meirion Hughes On

Basically, it doesn't look like you comprehensively check if one type if assignable another via reflection alone. The functionality to check if one type is assignable to another is already implemented in typescript, its just not exposed publicly and there is no real way to get at it without altering the typescript library manually.

One immediate workaround would be to effectively compile ad-hoc code to assign one to the other and see if there are compile errors.

The response to my request to expose isTypeAssignableTo has been favorable, so hopefully the answer will change in the near term.

[Update] it looks like it did eventually get exposed in a merge... I've not tried it though: https://github.com/microsoft/TypeScript/pull/33263/files#diff-c3ed224e4daa84352f7f1abcd23e8ccaR525-R527

0
JMac On

I'm not sure what a direct comparison to the C# isAssignableFrom method would be, but perhaps you could write your own logic to create that function -

isAssignableFrom(pullSymbol): boolean {
    ....
    if (typeof pullSymbol === 'string') {
        // Is compatible with any type that allows strings
    }
    ....
}

You can read on some of the language specifications here to find things like:

The Any type is a supertype of all types, and is assignable to and from all types.

Using that information with some hard-coded logic may be a solution for you.