@@ -8206,7 +8206,8 @@ namespace ts {
8206
8206
function isSignatureAssignableTo(source: Signature,
8207
8207
target: Signature,
8208
8208
ignoreReturnTypes: boolean): boolean {
8209
- return compareSignaturesRelated(source, target, ignoreReturnTypes, /*reportErrors*/ false, /*errorReporter*/ undefined, compareTypesAssignable) !== Ternary.False;
8209
+ return compareSignaturesRelated(source, target, /*checkAsCallback*/ false, ignoreReturnTypes, /*reportErrors*/ false,
8210
+ /*errorReporter*/ undefined, compareTypesAssignable) !== Ternary.False;
8210
8211
}
8211
8212
8212
8213
type ErrorReporter = (message: DiagnosticMessage, arg0?: string, arg1?: string) => void;
@@ -8216,6 +8217,7 @@ namespace ts {
8216
8217
*/
8217
8218
function compareSignaturesRelated(source: Signature,
8218
8219
target: Signature,
8220
+ checkAsCallback: boolean,
8219
8221
ignoreReturnTypes: boolean,
8220
8222
reportErrors: boolean,
8221
8223
errorReporter: ErrorReporter,
@@ -8258,9 +8260,23 @@ namespace ts {
8258
8260
const sourceParams = source.parameters;
8259
8261
const targetParams = target.parameters;
8260
8262
for (let i = 0; i < checkCount; i++) {
8261
- const s = i < sourceMax ? getTypeOfParameter(sourceParams[i]) : getRestTypeOfSignature(source);
8262
- const t = i < targetMax ? getTypeOfParameter(targetParams[i]) : getRestTypeOfSignature(target);
8263
- const related = compareTypes(s, t, /*reportErrors*/ false) || compareTypes(t, s, reportErrors);
8263
+ const sourceType = i < sourceMax ? getTypeOfParameter(sourceParams[i]) : getRestTypeOfSignature(source);
8264
+ const targetType = i < targetMax ? getTypeOfParameter(targetParams[i]) : getRestTypeOfSignature(target);
8265
+ const sourceSig = getSingleCallSignature(getNonNullableType(sourceType));
8266
+ const targetSig = getSingleCallSignature(getNonNullableType(targetType));
8267
+ // In order to ensure that any generic type Foo<T> is at least co-variant with respect to T no matter
8268
+ // how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions,
8269
+ // they naturally relate only contra-variantly). However, if the source and target parameters both have
8270
+ // function types with a single call signature, we known we are relating two callback parameters. In
8271
+ // that case it is sufficient to only relate the parameters of the signatures co-variantly because,
8272
+ // similar to return values, callback parameters are output positions. This means that a Promise<T>,
8273
+ // where T is used only in callback parameter positions, will be co-variant (as opposed to bi-variant)
8274
+ // with respect to T.
8275
+ const callbacks = sourceSig && targetSig && !sourceSig.typePredicate && !targetSig.typePredicate &&
8276
+ (getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable);
8277
+ const related = callbacks ?
8278
+ compareSignaturesRelated(targetSig, sourceSig, /*checkAsCallback*/ true, /*ignoreReturnTypes*/ false, reportErrors, errorReporter, compareTypes) :
8279
+ !checkAsCallback && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
8264
8280
if (!related) {
8265
8281
if (reportErrors) {
8266
8282
errorReporter(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
@@ -8292,7 +8308,11 @@ namespace ts {
8292
8308
}
8293
8309
}
8294
8310
else {
8295
- result &= compareTypes(sourceReturnType, targetReturnType, reportErrors);
8311
+ // When relating callback signatures, we still need to relate return types bi-variantly as otherwise
8312
+ // the containing type wouldn't be co-variant. For example, interface Foo<T> { add(cb: () => T): void }
8313
+ // wouldn't be co-variant for T without this rule.
8314
+ result &= checkAsCallback && compareTypes(targetReturnType, sourceReturnType, /*reportErrors*/ false) ||
8315
+ compareTypes(sourceReturnType, targetReturnType, reportErrors);
8296
8316
}
8297
8317
8298
8318
}
@@ -9260,7 +9280,7 @@ namespace ts {
9260
9280
* See signatureAssignableTo, compareSignaturesIdentical
9261
9281
*/
9262
9282
function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
9263
- return compareSignaturesRelated(source, target, /*ignoreReturnTypes*/ false, reportErrors, reportError, isRelatedTo);
9283
+ return compareSignaturesRelated(source, target, /*checkAsCallback*/ false, /* ignoreReturnTypes*/ false, reportErrors, reportError, isRelatedTo);
9264
9284
}
9265
9285
9266
9286
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
0 commit comments