@@ -27465,23 +27465,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2746527465 }
2746627466 return type;
2746727467 }
27468- const rightType = getTypeOfExpression(expr.right);
27469- // if rightType is an object type with a custom `[Symbol.hasInstance]` method, and that method has a type
27470- // predicate, use the type predicate to perform narrowing. This allows normal `object` types to participate
27471- // in `instanceof`, as per Step 2 of https://tc39.es/ecma262/#sec-instanceofoperator.
27472- const hasInstanceMethodType = getSymbolHasInstanceMethodOfObjectType(rightType);
27473- if (hasInstanceMethodType) {
27474- const syntheticCall = createSyntheticHasInstanceMethodCall(left, expr.right, type, hasInstanceMethodType);
27475- const signature = getEffectsSignature(syntheticCall);
27476- const predicate = signature && getTypePredicateOfSignature(signature);
27477- if (predicate && (predicate.kind === TypePredicateKind.This || predicate.kind === TypePredicateKind.Identifier)) {
27478- return narrowTypeByTypePredicate(type, predicate, syntheticCall, assumeTrue);
27479- }
27480- }
27481- if (!isTypeDerivedFrom(rightType, globalFunctionType)) {
27482- return type;
27483- }
27484- const instanceType = mapType(rightType, getInstanceType);
27468+ const right = expr.right;
27469+ const rightType = getTypeOfExpression(right);
27470+ const instanceType = mapType(rightType, t => getInstanceType(t, left, type, right));
2748527471 // Don't narrow from `any` if the target type is exactly `Object` or `Function`, and narrow
2748627472 // in the false branch only if the target is a non-empty object type.
2748727473 if (isTypeAny(type) && (instanceType === globalObjectType || instanceType === globalFunctionType) ||
@@ -27491,7 +27477,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2749127477 return getNarrowedType(type, instanceType, assumeTrue, /*checkDerived*/ true);
2749227478 }
2749327479
27494- function getInstanceType(constructorType: Type) {
27480+ function getInstanceType(constructorType: Type, left: Expression, leftType: Type, right: Expression) {
27481+ // if rightType is an object type with a custom `[Symbol.hasInstance]` method, and that method has a type
27482+ // predicate, use the type predicate to perform narrowing. This allows normal `object` types to participate
27483+ // in `instanceof`, as per Step 2 of https://tc39.es/ecma262/#sec-instanceofoperator.
27484+ const hasInstanceMethodType = getSymbolHasInstanceMethodOfObjectType(constructorType);
27485+ if (hasInstanceMethodType) {
27486+ const syntheticCall = createSyntheticHasInstanceMethodCall(left, leftType, right, constructorType, hasInstanceMethodType);
27487+ const signature = getEffectsSignature(syntheticCall);
27488+ const predicate = signature && getTypePredicateOfSignature(signature);
27489+ if (predicate && predicate.kind == TypePredicateKind.Identifier && predicate.parameterIndex == 0) {
27490+ return predicate.type;
27491+ }
27492+ if (!isTypeDerivedFrom(constructorType, globalFunctionType)) {
27493+ return leftType;
27494+ }
27495+ }
2749527496 const prototypePropertyType = getTypeOfPropertyOfType(constructorType, "prototype" as __String);
2749627497 if (prototypePropertyType && !isTypeAny(prototypePropertyType)) {
2749727498 return prototypePropertyType;
@@ -27575,17 +27576,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2757527576 function narrowTypeByTypePredicate(type: Type, predicate: TypePredicate, callExpression: CallExpression, assumeTrue: boolean): Type {
2757627577 // Don't narrow from 'any' if the predicate type is exactly 'Object' or 'Function'
2757727578 if (predicate.type && !(isTypeAny(type) && (predicate.type === globalObjectType || predicate.type === globalFunctionType))) {
27578- let predicateArgument = getTypePredicateArgument(predicate, callExpression);
27579+ const predicateArgument = getTypePredicateArgument(predicate, callExpression);
2757927580 if (predicateArgument) {
27580- // If the predicate argument is synthetic and is the first argument of a synthetic call to
27581- // `[Symbol.hasInstance]`, replace the synthetic predicate argument with the actual argument from
27582- // the original `instanceof` expression which is stored as the synthetic argument's `parent`.
27583- if (isSyntheticExpression(predicateArgument) &&
27584- predicate.parameterIndex === 0 &&
27585- isSyntheticHasInstanceMethodCall(callExpression)) {
27586- Debug.assertNode(predicateArgument.parent, isExpression);
27587- predicateArgument = predicateArgument.parent;
27588- }
2758927581 if (isMatchingReference(reference, predicateArgument)) {
2759027582 return getNarrowedType(type, predicate.type, assumeTrue, /*checkDerived*/ false);
2759127583 }
@@ -32891,11 +32883,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3289132883 if (isAccessExpression(callee)) {
3289232884 return callee.expression;
3289332885 }
32886+ if (isSyntheticExpression(callee)) {
32887+ return callee.thisArgument;
32888+ }
3289432889 }
3289532890 }
3289632891
32897- function createSyntheticExpression(parent: Node, type: Type, isSpread?: boolean, tupleNameSource?: ParameterDeclaration | NamedTupleMember) {
32898- const result = parseNodeFactory.createSyntheticExpression(type, isSpread, tupleNameSource);
32892+ function createSyntheticExpression(parent: Node, type: Type, isSpread?: boolean, tupleNameSource?: ParameterDeclaration | NamedTupleMember, thisArgument?: LeftHandSideExpression ) {
32893+ const result = parseNodeFactory.createSyntheticExpression(type, isSpread, tupleNameSource, thisArgument );
3289932894 setTextRange(result, parent);
3290032895 setParent(result, parent);
3290132896 return result;
@@ -36498,8 +36493,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3649836493 * @param leftType The type of the left-hand expression of `instanceof`.
3649936494 * @param hasInstanceMethodType The type of the `[Symbol.hasInstance]` method of the right-hand expression of `instanceof`.
3650036495 */
36501- function createSyntheticHasInstanceMethodCall(left: Expression, right: Expression, leftType: Type, hasInstanceMethodType: Type) {
36502- const syntheticExpression = createSyntheticExpression(right, hasInstanceMethodType);
36496+ function createSyntheticHasInstanceMethodCall(left: Expression, leftType: Type, right: Expression, rightType: Type, hasInstanceMethodType: Type) {
36497+ const thisArgument = createSyntheticExpression(right, rightType);
36498+ const syntheticExpression = createSyntheticExpression(right, hasInstanceMethodType, /*isSpread*/ false, /*tupleNameSource*/ undefined, thisArgument);
3650336499 const syntheticArgument = createSyntheticExpression(left, leftType);
3650436500 const syntheticCall = parseNodeFactory.createCallExpression(syntheticExpression, /*typeArguments*/ undefined, [syntheticArgument]);
3650536501 setParent(syntheticCall, left.parent);
@@ -36556,7 +36552,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3655636552 // must check the expression as if it were a call to `right[Symbol.hasInstance](left)1. The call to
3655736553 // `getResolvedSignature`, below, will check that leftType is assignable to the type of the first
3655836554 // parameter.
36559- const syntheticCall = createSyntheticHasInstanceMethodCall(left, right, leftType , hasInstanceMethodType);
36555+ const syntheticCall = createSyntheticHasInstanceMethodCall(left, leftType, right, rightType , hasInstanceMethodType);
3656036556 const returnType = getReturnTypeOfSignature(getResolvedSignature(syntheticCall));
3656136557
3656236558 // We also verify that the return type of the `[Symbol.hasInstance]` method is assignable to
0 commit comments