TypescriptIndexedAccessJSType type substitution when pointing to generic

Answered

I'm currently building an "Implement all members" intention to get more familiar with the JS/TS API. I'm unsure how to resolve/substitute a `this` index access type that points to a generic. Given the Typescript code:

interface MyInterface<T> {
a: T;
b: this["a"];
}

function takesGeneric<T>(x: MyInterface<T>): number {
return 0;
}
const obj1 = takesGeneric<string>({<spot></spot>});

and the intention:

class ImplementMembersIntention : PsiElementBaseIntentionAction() {

override fun getText(): String {
return "Implement members"
}

override fun getFamilyName(): String {
return "ImplementMembersIntention"
}

override fun isAvailable(project: Project, editor: Editor?, element: PsiElement): Boolean {
val parent = element.parent
val parentContext = parent.context
return (parentContext is JSArgumentListImpl && parent is JSObjectLiteralExpressionImpl)
}

override fun invoke(project: Project, editor: Editor?, element: PsiElement) {
val objLiteral = element.parent as JSObjectLiteralExpressionImpl
val argList = objLiteral.context as JSArgumentListImpl
val objLiteralIdx = argList.arguments.indexOf(objLiteral)
val functionCall = argList.parent as JSCallExpressionImpl
// expectedType: "MyInterface<string>"
val expectedType = TypeScriptExpectedTypeEvaluator.handleFunctionCallType(functionCall, objLiteralIdx, JSExpectedTypeKind.EXPECTED) as JSGenericTypeImpl
val recordType = expectedType.asRecordType()
val memberB = recordType.typeMembers[1] as TypeScriptPropertySignatureImpl
val indexAccessTypeB = memberB.jsType as TypeScriptIndexedAccessJSTypeImpl

// How do I resolve this to be JSStringType instead of JSUnknownType?
val expectedJSStringType = indexAccessTypeB.substituteCompletely() // "unknown"

objLiteral.replace(JSPsiElementFactory.createJSExpression("{/* TODO */}",argList))
}
}

I'm unsure how to approach substituting `this["a"]` with `string`. I've tried building a `JSTypeSubstitutionContext` and passing it into `.substitute(...)` but I seem to end up with a `JSUnknownType` whenever it points to a generic type. What is the correct way to apply the generic context to the substitution?

1 comment
Comment actions Permalink

Hi! The method

indexAccessTypeB.substituteCompletely()

does the job. Unfortunately, WebStorm's type evaluator has a bug, and because of that, the "this" type in the interface cannot be handled properly. 

0

Please sign in to leave a comment.