@@ -8157,7 +8157,7 @@ namespace ts {
8157
8157
function isSignatureAssignableTo(source: Signature,
8158
8158
target: Signature,
8159
8159
ignoreReturnTypes: boolean): boolean {
8160
- return compareSignaturesRelated(source, target, /*strictVariance */ false, ignoreReturnTypes, /*reportErrors*/ false,
8160
+ return compareSignaturesRelated(source, target, /*checkAsCallback */ false, ignoreReturnTypes, /*reportErrors*/ false,
8161
8161
/*errorReporter*/ undefined, compareTypesAssignable) !== Ternary.False;
8162
8162
}
8163
8163
@@ -8168,7 +8168,7 @@ namespace ts {
8168
8168
*/
8169
8169
function compareSignaturesRelated(source: Signature,
8170
8170
target: Signature,
8171
- strictVariance : boolean,
8171
+ checkAsCallback : boolean,
8172
8172
ignoreReturnTypes: boolean,
8173
8173
reportErrors: boolean,
8174
8174
errorReporter: ErrorReporter,
@@ -8215,13 +8215,17 @@ namespace ts {
8215
8215
const targetType = i < targetMax ? getTypeOfParameter(targetParams[i]) : getRestTypeOfSignature(target);
8216
8216
const sourceSig = getSingleCallSignature(sourceType);
8217
8217
const targetSig = getSingleCallSignature(targetType);
8218
- // If the source and target parameters both have function types with a single call signature we are
8219
- // relating two callback parameters. In that case we compare the callback signatures with strict
8220
- // variance, meaning we require the callback parameters to be pairwise co-variant (because, similar
8221
- // to return values, callback parameters are output positions).
8222
- const related = sourceSig && targetSig ?
8223
- compareSignaturesRelated(targetSig, sourceSig, /*strictVariance*/ true, /*ignoreReturnTypes*/ false, reportErrors, errorReporter, compareTypes) :
8224
- !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
8218
+ // In order to ensure that any generic type Foo<T> is at least co-variant with respect to T no matter
8219
+ // how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions,
8220
+ // they naturally relate only contra-variantly). However, if the source and target parameters both have
8221
+ // function types with a single call signature, we known we are relating two callback parameters. In
8222
+ // that case it is sufficient to only relate the parameters of the signatures co-variantly because,
8223
+ // similar to return values, callback parameters are output positions. This means that a Promise<T>,
8224
+ // where T is used only in callback parameter positions, will be co-variant (as opposed to bi-variant)
8225
+ // with respect to T.
8226
+ const related = sourceSig && targetSig && !sourceSig.typePredicate && !targetSig.typePredicate ?
8227
+ compareSignaturesRelated(targetSig, sourceSig, /*checkAsCallback*/ true, /*ignoreReturnTypes*/ false, reportErrors, errorReporter, compareTypes) :
8228
+ !checkAsCallback && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
8225
8229
if (!related) {
8226
8230
if (reportErrors) {
8227
8231
errorReporter(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
@@ -8253,7 +8257,11 @@ namespace ts {
8253
8257
}
8254
8258
}
8255
8259
else {
8256
- result &= compareTypes(sourceReturnType, targetReturnType, reportErrors);
8260
+ // When relating callback signatures, we still need to relate return types bi-variantly as otherwise
8261
+ // the containing type wouldn't be co-variant. For example, interface Foo<T> { add(cb: () => T): void }
8262
+ // wouldn't be co-variant for T without this rule.
8263
+ result &= checkAsCallback && compareTypes(targetReturnType, sourceReturnType, /*reportErrors*/ false) ||
8264
+ compareTypes(sourceReturnType, targetReturnType, reportErrors);
8257
8265
}
8258
8266
8259
8267
}
@@ -9220,7 +9228,7 @@ namespace ts {
9220
9228
* See signatureAssignableTo, compareSignaturesIdentical
9221
9229
*/
9222
9230
function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
9223
- return compareSignaturesRelated(source, target, /*strictVariance */ false, /*ignoreReturnTypes*/ false, reportErrors, reportError, isRelatedTo);
9231
+ return compareSignaturesRelated(source, target, /*checkAsCallback */ false, /*ignoreReturnTypes*/ false, reportErrors, reportError, isRelatedTo);
9224
9232
}
9225
9233
9226
9234
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
0 commit comments