5

With this code (playground):

declare class Test<P = unknown, R = unknown> {
    test(p: P): R;
}

declare class M extends Test {
    test(q: number): boolean;
}

// these lines are not in real code. This is an example of what TS
// could infer from my code and what I would like to find using Compiler API
type Sgn<M> = M extends Test<infer P, infer R> ? [P, R] : never;
type sgn = Sgn<M>; // [number, boolean]

typescript could infer implicit type arguments of class M (P = number, R = boolean) from method test in class declaration.

I want to do the same using Compiler API. I have program.typeChecker and I'm stuck here. How could I get implicit type arguments?

2 Answers 2

3

The type Test in extends Test of M is not implicitly typed as Test<number, boolean>. The class M overwrites the declaration of test to be test(q: number): boolean. If you get the type of the ExpressionWithTypeArguemnts in extends Test of M it will be Test<unknown, unknown>.

Getting Types from M

If you know what the structure of Test is and you have...

declare class M extends Test {
    test(q: number): boolean;
}

...and you want to find the type of the parameter and the return type of test, then you can do the following:

const mDecl = sourceFile.statements.find(child =>
    ts.isClassDeclaration(child) && child.name?.escapedText === "M"
)! as ts.ClassDeclaration;
const testMethod = mDecl.members.find(member =>
    ts.isMethodDeclaration(member)
    && ts.isIdentifier(member.name)
    && member.name.escapedText === "test"
)! as ts.MethodDeclaration;

// number type
typeChecker.getTypeAtLocation(testMethod.parameters[0]);
// boolean type
typeChecker.getReturnTypeOfSignature(typeChecker.getSignatureFromDeclaration(testMethod));

Given Test, finding P and R in M

If you have Test and want to find P and R in M and you don't know what the type of Test might look like, then you cannot use the previously described method.

To do this, you will have to traverse the type of Test manually and then traverse M in the same way and see what type the type parameters in Test are used in M. Doing this is kind of complicated and would be too much work/code to post here.

Basically, there's no easy way to build up types and then do comparisons with the compiler API. There are some proposals to make this easier (ex. Type Builder API Proposal and Type Relationship API Proposal).

That said, one way around it is to create a dummy file via ts.createSourceFile and write some code in there (ex. your Sgn and sgn declarations) then use the type checker on that file to resolve the types.

Sign up to request clarification or add additional context in comments.

4 Comments

Sgn in question is just for reference what TS could infer and I would like to get without it.
I see in other words, you're suggesting to get type of test method
If I use a dummy file, I could find a way to add it to existing program. Do I have to create another program?
Nevermind. I've found doc comment A Program is an immutable collection
0

There is a new library that bring types to the runtime world https://deepkit.io/. You can use it to infer any type in your code.

It is a full framework but you can use the @deepkit/types and @deekit/type-compiler for what you want.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.