Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork2.8k
Description
Suggestion
Sadly, right nowgetConstrainedTypeOfLocation
is bugged for unconstrained generics. The code just gives back the type parameter type if getBaseConstraintOfType(nodeType) is nullish, but that's not correct. Unconstrained generics should behave likeunknown
. Here's what it is right now:
/** | |
* Resolves the given node's type. Will resolve to the type's generic constraint, if it has one. | |
*/ | |
exportfunctiongetConstrainedTypeAtLocation( | |
services:ParserServicesWithTypeInformation, | |
node:TSESTree.Node, | |
):ts.Type{ | |
constnodeType=services.getTypeAtLocation(node); | |
constconstrained=services.program | |
.getTypeChecker() | |
.getBaseConstraintOfType(nodeType); | |
returnconstrained??nodeType; | |
} |
And here's what it "should" be:
/** * Resolves the given node's type. Will resolve to the type's generic constraint, if it has one. */exportfunctiongetConstrainedTypeAtLocation(services:ParserServicesWithTypeInformation,node:TSESTree.Node,):ts.Type{constnodeType=services.getTypeAtLocation(node);if(tsutils.isTypeParameter(nodeType)){constchecker=services.program.getTypeChecker();return(checker.getBaseConstraintOfType(nodeType)??checker.getUnknownType());}returnnodeType;}
Unfortunately, due tomicrosoft/TypeScript#60475, there is nochecker.getUnknownType()
yet or for a while.
It kind of sucks, but I propose that we instead modify the implementation to something more like
exportfunctiongetConstrainedTypeAtLocation(services:ParserServicesWithTypeInformation,node:TSESTree.Node,):ts.Type|undefined{// <-- note the `| undefined`constnodeType=services.getTypeAtLocation(node);if(tsutils.isTypeParameter(nodeType)){constchecker=services.program.getTypeChecker();returnchecker.getBaseConstraintOfType(nodeType)/* in the future this can have ?? checker.getUnknownType() */;}returnnodeType;}
and force callers to handle the unconstrained case separately.
Note - I think we should also double-check (and add tests) for what happens when the constraint isany
. I'm pretty surefunction f<T extends any>(x: T) {}
behaves as thoughT
wereunknown
rather thanany
. So maybe we should really be doing
exportfunctiongetConstrainedTypeAtLocation(services:ParserServicesWithTypeInformation,node:TSESTree.Node,):ts.Type|undefined{constnodeType=services.getTypeAtLocation(node);if(tsutils.isTypeParameter(nodeType)){constchecker=services.program.getTypeChecker();constconstraint=checker.getBaseConstraintOfType(nodeType);returnconstraint==null||isTypeAnyType(constraint) ?/* in the future this can be checker.getUnknownType() */undefined :constraint;}returnnodeType;}
I haven't yet checked whatchecker.getBaseConstraintOfType()
does with anany
.
Additional Info
Related, caused#10311
Related, discussion at#10314 (comment)
Possibly related,#10415
cc@ronami