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?
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.