diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6ece23f022a..c2603e1f30b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23593,7 +23593,20 @@ namespace ts { // If the signature's 'this' type is voidType, then the check is skipped -- anything is compatible. // If the expression is a new expression, then the check is skipped. const thisArgumentNode = getThisArgumentOfCall(node); - const thisArgumentType = thisArgumentNode ? checkExpression(thisArgumentNode) : voidType; + let thisArgumentType: Type; + if (thisArgumentNode) { + thisArgumentType = checkExpression(thisArgumentNode); + if (isOptionalChainRoot(thisArgumentNode.parent)) { + thisArgumentType = getNonNullableType(thisArgumentType); + } + else if (isOptionalChain(thisArgumentNode.parent)) { + thisArgumentType = removeOptionalTypeMarker(thisArgumentType); + } + } + else { + thisArgumentType = voidType; + } + const errorNode = reportErrors ? (thisArgumentNode || node) : undefined; const headMessage = Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1; if (!checkTypeRelatedTo(thisArgumentType, thisType, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer)) { diff --git a/tests/baselines/reference/thisTypeOptionalCall.js b/tests/baselines/reference/thisTypeOptionalCall.js new file mode 100644 index 00000000000..2a7a24d6eeb --- /dev/null +++ b/tests/baselines/reference/thisTypeOptionalCall.js @@ -0,0 +1,10 @@ +//// [thisTypeOptionalCall.ts] +function maybeBind(obj: T, fn: ((this: T, ...args: A) => R) | undefined): ((...args: A) => R) | undefined { + return fn?.bind(obj); +} + +//// [thisTypeOptionalCall.js] +function maybeBind(obj, fn) { + var _a; + return (_a = fn) === null || _a === void 0 ? void 0 : _a.bind(obj); +} diff --git a/tests/baselines/reference/thisTypeOptionalCall.symbols b/tests/baselines/reference/thisTypeOptionalCall.symbols new file mode 100644 index 00000000000..d55d8c823c1 --- /dev/null +++ b/tests/baselines/reference/thisTypeOptionalCall.symbols @@ -0,0 +1,24 @@ +=== tests/cases/conformance/types/thisType/thisTypeOptionalCall.ts === +function maybeBind(obj: T, fn: ((this: T, ...args: A) => R) | undefined): ((...args: A) => R) | undefined { +>maybeBind : Symbol(maybeBind, Decl(thisTypeOptionalCall.ts, 0, 0)) +>T : Symbol(T, Decl(thisTypeOptionalCall.ts, 0, 19)) +>A : Symbol(A, Decl(thisTypeOptionalCall.ts, 0, 21)) +>R : Symbol(R, Decl(thisTypeOptionalCall.ts, 0, 38)) +>obj : Symbol(obj, Decl(thisTypeOptionalCall.ts, 0, 42)) +>T : Symbol(T, Decl(thisTypeOptionalCall.ts, 0, 19)) +>fn : Symbol(fn, Decl(thisTypeOptionalCall.ts, 0, 49)) +>this : Symbol(this, Decl(thisTypeOptionalCall.ts, 0, 56)) +>T : Symbol(T, Decl(thisTypeOptionalCall.ts, 0, 19)) +>args : Symbol(args, Decl(thisTypeOptionalCall.ts, 0, 64)) +>A : Symbol(A, Decl(thisTypeOptionalCall.ts, 0, 21)) +>R : Symbol(R, Decl(thisTypeOptionalCall.ts, 0, 38)) +>args : Symbol(args, Decl(thisTypeOptionalCall.ts, 0, 99)) +>A : Symbol(A, Decl(thisTypeOptionalCall.ts, 0, 21)) +>R : Symbol(R, Decl(thisTypeOptionalCall.ts, 0, 38)) + + return fn?.bind(obj); +>fn?.bind : Symbol(Function.bind, Decl(lib.es5.d.ts, --, --)) +>fn : Symbol(fn, Decl(thisTypeOptionalCall.ts, 0, 49)) +>bind : Symbol(Function.bind, Decl(lib.es5.d.ts, --, --)) +>obj : Symbol(obj, Decl(thisTypeOptionalCall.ts, 0, 42)) +} diff --git a/tests/baselines/reference/thisTypeOptionalCall.types b/tests/baselines/reference/thisTypeOptionalCall.types new file mode 100644 index 00000000000..1c2a9cd7020 --- /dev/null +++ b/tests/baselines/reference/thisTypeOptionalCall.types @@ -0,0 +1,16 @@ +=== tests/cases/conformance/types/thisType/thisTypeOptionalCall.ts === +function maybeBind(obj: T, fn: ((this: T, ...args: A) => R) | undefined): ((...args: A) => R) | undefined { +>maybeBind : (obj: T, fn: ((this: T, ...args: A) => R) | undefined) => ((...args: A) => R) | undefined +>obj : T +>fn : ((this: T, ...args: A) => R) | undefined +>this : T +>args : A +>args : A + + return fn?.bind(obj); +>fn?.bind(obj) : any +>fn?.bind : ((this: Function, thisArg: any, ...argArray: any[]) => any) | undefined +>fn : ((this: T, ...args: A) => R) | undefined +>bind : ((this: Function, thisArg: any, ...argArray: any[]) => any) | undefined +>obj : T +} diff --git a/tests/cases/conformance/types/thisType/thisTypeOptionalCall.ts b/tests/cases/conformance/types/thisType/thisTypeOptionalCall.ts new file mode 100644 index 00000000000..b3f35a596ea --- /dev/null +++ b/tests/cases/conformance/types/thisType/thisTypeOptionalCall.ts @@ -0,0 +1,8 @@ +// @strictNullChecks: true +// @noImplicitAny: true +// @noImplicitThis: true +// @strictBindCallApply: false + +function maybeBind(obj: T, fn: ((this: T, ...args: A) => R) | undefined): ((...args: A) => R) | undefined { + return fn?.bind(obj); +} \ No newline at end of file