diff --git a/src/compiler.ts b/src/compiler.ts index a2b313603b..6955383478 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -6609,17 +6609,18 @@ export class Compiler extends DiagnosticEmitter { for (let i = 0, k = overrideInstances.length; i < k; ++i) { let overrideInstance = overrideInstances[i]; if (!overrideInstance.is(CommonFlags.Compiled)) continue; // errored - let overrideType = overrideInstance.type; - let originalType = instance.type; - if (!overrideType.isAssignableTo(originalType)) { + + let overrideSignature = overrideInstance.signature; + let originalSignature = instance.signature; + + if (!overrideSignature.isAssignableTo(originalSignature, true)) { this.error( DiagnosticCode.Type_0_is_not_assignable_to_type_1, - overrideInstance.identifierNode.range, overrideType.toString(), originalType.toString() + overrideInstance.identifierNode.range, overrideSignature.toString(), originalSignature.toString() ); continue; } // TODO: additional optional parameters are not permitted by `isAssignableTo` yet - let overrideSignature = overrideInstance.signature; let overrideParameterTypes = overrideSignature.parameterTypes; let overrideNumParameters = overrideParameterTypes.length; let paramExprs = new Array(1 + overrideNumParameters); diff --git a/src/types.ts b/src/types.ts index 4aef00a5b2..675e9c7ee7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1051,22 +1051,14 @@ export class Signature { isAssignableTo(target: Signature, checkCompatibleOverride: bool = false): bool { let thisThisType = this.thisType; let targetThisType = target.thisType; - if (checkCompatibleOverride) { - // check kind of `this` type - if (thisThisType) { - if (!targetThisType || !thisThisType.canExtendOrImplement(targetThisType)) { - return false; - } - } else if (targetThisType) { - return false; - } - } else { - // check `this` type (invariant) - if (thisThisType) { - if (targetThisType != targetThisType) return false; - } else if (targetThisType) { - return false; - } + + if (thisThisType && targetThisType) { + const compatibleThisType = checkCompatibleOverride + ? thisThisType.canExtendOrImplement(targetThisType) + : targetThisType.isAssignableTo(thisThisType); + if (!compatibleThisType) return false; + } else if (thisThisType || targetThisType) { + return false; } // check rest parameter diff --git a/tests/compiler/class-member-function-as-parameter.json b/tests/compiler/class-member-function-as-parameter.json new file mode 100644 index 0000000000..38ccfe0479 --- /dev/null +++ b/tests/compiler/class-member-function-as-parameter.json @@ -0,0 +1,8 @@ +{ + "asc_flags": [], + "stderr": [ + "TS2322: Type '() => void' is not assignable to type '(this: class-member-function-as-parameter/A) => void'.", + "TS2322: Type '(this: class-member-function-as-parameter/B) => void' is not assignable to type '(this: class-member-function-as-parameter/A) => void'.", + "EOF" + ] +} diff --git a/tests/compiler/class-member-function-as-parameter.ts b/tests/compiler/class-member-function-as-parameter.ts new file mode 100644 index 0000000000..611f0fbf03 --- /dev/null +++ b/tests/compiler/class-member-function-as-parameter.ts @@ -0,0 +1,20 @@ +class A { + foo(): void { } +} + +class B extends A { + foo(): void { } +} + +function foo(): void { } + +function consumeA(callback: (this: A) => void): void { } +function consumeB(callback: (this: B) => void): void { } + +const a = new A(); +const b = new B(); + +consumeB(a.foo); // shouldn't error +consumeA(foo); // should error +consumeA(b.foo); // should error +ERROR("EOF"); \ No newline at end of file