@@ -34120,6 +34120,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3412034120 result = chooseOverload(candidates, assignableRelation, isSingleNonGenericCandidate, signatureHelpTrailingComma);
3412134121 }
3412234122 if (result) {
34123+ const returnType = calculateSignatureReturnTypeForSpecialCases(result, args);
34124+ if (returnType) {
34125+ result = cloneSignature(result);
34126+ result.resolvedReturnType = returnType;
34127+ }
3412334128 return result;
3412434129 }
3412534130
@@ -34235,6 +34240,70 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3423534240
3423634241 return result;
3423734242
34243+ function calculateSignatureReturnTypeForSpecialCases(signature: Readonly<Signature>, args: readonly Expression[]): Type | undefined {
34244+ if (args.length >= 1) {
34245+ // In some tsx cases "symbol" is undefined, even though it is defined in the typechecker. So add ?
34246+ if (
34247+ signature.declaration?.symbol?.escapedName === "filter" && (
34248+ signature.declaration?.symbol?.parent?.escapedName === "Array"
34249+ || signature.declaration?.symbol?.parent?.escapedName === "ReadonlyArray"
34250+ )
34251+ ) {
34252+ const arg0Type = getTypeOfExpression(args[0]);
34253+ // This is safe even if a different BooleanConstructor is defined in a namespace,
34254+ // because in that case arg0Type.symbol.escapedName will appear as "__type".
34255+ if (arg0Type.symbol.escapedName === "BooleanConstructor") {
34256+ // It is a-priori knowledge the filter returns the same type as the array type
34257+ // for a signature succeeding when BooleanConstructor is the argument type
34258+ let returnType = (signature.mapper as undefined | { targets: readonly Type[]; })?.targets[1];
34259+ // result.declaration?.symbol.parent?.escapedName==="ReadonlyArray"
34260+ if (returnType) {
34261+ const nonFalsieArrayTypesOut: Type[] = [];
34262+ // the return type can only be an array type.
34263+ // It cant actually be a union of array types for a single signature.
34264+ // So this forEachType could be skipped, but may be used in the future with union of array types
34265+ forEachType(returnType, at => {
34266+ let elemType: Type;
34267+ if (isTupleType(at)) {
34268+ // The tuple elements are unionized, *abondoning* the tupleness becuase
34269+ // filtering could create result of varying length.
34270+ // For variable length tuples, undefined is *not* added to the union within getElementTypes.
34271+ elemType = getUnionType(getElementTypes(at));
34272+ }
34273+ else if (isTupleLikeType(at)) {
34274+ // doesn't handle tupleLikeTypes
34275+ // just return the orginal type
34276+ nonFalsieArrayTypesOut.push(at);
34277+ return;
34278+ }
34279+ else {
34280+ elemType = getElementTypeOfArrayType(at) || anyType; // need test case for anyType
34281+ }
34282+ const nonFalsieElemTypes: Type[] = [];
34283+ nonFalsieElemTypes.push(filterType(
34284+ elemType,
34285+ t => {
34286+ const facts = getTypeFacts(t, TypeFacts.Truthy | TypeFacts.Falsy);
34287+ if (facts === TypeFacts.Falsy) {
34288+ return false;
34289+ }
34290+ else {
34291+ return true;
34292+ }
34293+ },
34294+ ));
34295+ // output arrays are not not readonly
34296+ const atout = createArrayType(getUnionType(nonFalsieElemTypes));
34297+ nonFalsieArrayTypesOut.push(atout);
34298+ });
34299+ returnType = getUnionType(nonFalsieArrayTypesOut);
34300+ return returnType;
34301+ }
34302+ }
34303+ }
34304+ }
34305+ }
34306+
3423834307 function addImplementationSuccessElaboration(failed: Signature, diagnostic: Diagnostic) {
3423934308 const oldCandidatesForArgumentError = candidatesForArgumentError;
3424034309 const oldCandidateForArgumentArityError = candidateForArgumentArityError;
0 commit comments