Extended support for bidirectional type inference for functions that have a generic return type and the "expected type" is a generic class with type arguments that include literal types.

This commit is contained in:
Eric Traut 2021-10-27 23:41:32 -07:00
parent 6d3d1279ab
commit bc338c643c
2 changed files with 14 additions and 3 deletions

View File

@ -8103,7 +8103,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
// If the expected type is a union, we don't know which type is expected,
// so avoid using the expected type. The exception is if there are literals
// in the union, where it's important to prepopulate the literals.
if (!isUnion(expectedType) || containsLiteralType(expectedType)) {
if (!isUnion(expectedType) || containsLiteralType(expectedType, /* includeTypeArgs */ true)) {
// Prepopulate the typeVarMap based on the specialized expected type if the
// callee has a declared return type. This will allow us to more closely match
// the expected type if possible. We set the AllowTypeVarNarrowing and

View File

@ -590,13 +590,24 @@ export function isLiteralTypeOrUnion(type: Type): boolean {
return false;
}
export function containsLiteralType(type: Type): boolean {
export function containsLiteralType(type: Type, includeTypeArgs = false, recursionCount = 0): boolean {
if (recursionCount > maxTypeRecursionCount) {
return false;
}
if (isClassInstance(type) && isLiteralType(type)) {
return true;
}
if (includeTypeArgs && isClass(type)) {
const typeArgs = type.tupleTypeArguments || type.typeArguments;
if (typeArgs) {
return typeArgs.some((typeArg) => containsLiteralType(typeArg, includeTypeArgs, recursionCount + 1));
}
}
if (isUnion(type)) {
return type.subtypes.some((subtype) => isClassInstance(subtype) && isLiteralType(subtype));
return type.subtypes.some((subtype) => containsLiteralType(subtype, includeTypeArgs, recursionCount + 1));
}
return false;