mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
Merge pull request #18976 from Microsoft/strictCallbackParameters
Strictly check callback parameters
This commit is contained in:
commit
b7e744a0e5
@ -503,6 +503,12 @@ namespace ts {
|
||||
Inferential = 2, // Inferential typing
|
||||
}
|
||||
|
||||
const enum CallbackCheck {
|
||||
None,
|
||||
Bivariant,
|
||||
Strict,
|
||||
}
|
||||
|
||||
const builtinGlobals = createSymbolTable();
|
||||
builtinGlobals.set(undefinedSymbol.escapedName, undefinedSymbol);
|
||||
|
||||
@ -8510,7 +8516,7 @@ namespace ts {
|
||||
function isSignatureAssignableTo(source: Signature,
|
||||
target: Signature,
|
||||
ignoreReturnTypes: boolean): boolean {
|
||||
return compareSignaturesRelated(source, target, /*checkAsCallback*/ false, ignoreReturnTypes, /*reportErrors*/ false,
|
||||
return compareSignaturesRelated(source, target, CallbackCheck.None, ignoreReturnTypes, /*reportErrors*/ false,
|
||||
/*errorReporter*/ undefined, compareTypesAssignable) !== Ternary.False;
|
||||
}
|
||||
|
||||
@ -8521,7 +8527,7 @@ namespace ts {
|
||||
*/
|
||||
function compareSignaturesRelated(source: Signature,
|
||||
target: Signature,
|
||||
checkAsCallback: boolean,
|
||||
callbackCheck: CallbackCheck,
|
||||
ignoreReturnTypes: boolean,
|
||||
reportErrors: boolean,
|
||||
errorReporter: ErrorReporter,
|
||||
@ -8540,7 +8546,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown;
|
||||
const strictVariance = strictFunctionTypes && kind !== SyntaxKind.MethodDeclaration &&
|
||||
const strictVariance = !callbackCheck && strictFunctionTypes && kind !== SyntaxKind.MethodDeclaration &&
|
||||
kind !== SyntaxKind.MethodSignature && kind !== SyntaxKind.Constructor;
|
||||
let result = Ternary.True;
|
||||
|
||||
@ -8582,8 +8588,8 @@ namespace ts {
|
||||
const callbacks = sourceSig && targetSig && !sourceSig.typePredicate && !targetSig.typePredicate &&
|
||||
(getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable);
|
||||
const related = callbacks ?
|
||||
compareSignaturesRelated(targetSig, sourceSig, /*checkAsCallback*/ true, /*ignoreReturnTypes*/ false, reportErrors, errorReporter, compareTypes) :
|
||||
!checkAsCallback && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
|
||||
compareSignaturesRelated(targetSig, sourceSig, strictVariance ? CallbackCheck.Strict : CallbackCheck.Bivariant, /*ignoreReturnTypes*/ false, reportErrors, errorReporter, compareTypes) :
|
||||
!callbackCheck && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
|
||||
if (!related) {
|
||||
if (reportErrors) {
|
||||
errorReporter(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
|
||||
@ -8618,7 +8624,7 @@ namespace ts {
|
||||
// When relating callback signatures, we still need to relate return types bi-variantly as otherwise
|
||||
// the containing type wouldn't be co-variant. For example, interface Foo<T> { add(cb: () => T): void }
|
||||
// wouldn't be co-variant for T without this rule.
|
||||
result &= checkAsCallback && compareTypes(targetReturnType, sourceReturnType, /*reportErrors*/ false) ||
|
||||
result &= callbackCheck === CallbackCheck.Bivariant && compareTypes(targetReturnType, sourceReturnType, /*reportErrors*/ false) ||
|
||||
compareTypes(sourceReturnType, targetReturnType, reportErrors);
|
||||
}
|
||||
|
||||
@ -9726,7 +9732,7 @@ namespace ts {
|
||||
*/
|
||||
function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean): Ternary {
|
||||
return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target,
|
||||
/*checkAsCallback*/ false, /*ignoreReturnTypes*/ false, reportErrors, reportError, isRelatedTo);
|
||||
CallbackCheck.None, /*ignoreReturnTypes*/ false, reportErrors, reportError, isRelatedTo);
|
||||
}
|
||||
|
||||
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
|
||||
|
||||
@ -87,9 +87,24 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(126,1): error TS2322: Type 'Cr
|
||||
tests/cases/compiler/strictFunctionTypesErrors.ts(127,1): error TS2322: Type 'Crate<Animal>' is not assignable to type 'Crate<Dog>'.
|
||||
Types of property 'item' are incompatible.
|
||||
Type 'Animal' is not assignable to type 'Dog'.
|
||||
tests/cases/compiler/strictFunctionTypesErrors.ts(133,1): error TS2322: Type '(f: (x: Dog) => Dog) => void' is not assignable to type '(f: (x: Animal) => Animal) => void'.
|
||||
Types of parameters 'f' and 'f' are incompatible.
|
||||
Type 'Animal' is not assignable to type 'Dog'.
|
||||
tests/cases/compiler/strictFunctionTypesErrors.ts(134,1): error TS2322: Type '(f: (x: Animal) => Animal) => void' is not assignable to type '(f: (x: Dog) => Dog) => void'.
|
||||
Types of parameters 'f' and 'f' are incompatible.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type 'Animal' is not assignable to type 'Dog'.
|
||||
tests/cases/compiler/strictFunctionTypesErrors.ts(147,5): error TS2322: Type '(cb: (x: Animal) => Animal) => void' is not assignable to type '(cb: (x: Dog) => Animal) => void'.
|
||||
Types of parameters 'cb' and 'cb' are incompatible.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type 'Animal' is not assignable to type 'Dog'.
|
||||
tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(cb: (x: Animal) => Animal) => void' is not assignable to type '(cb: (x: Dog) => Animal) => void'.
|
||||
Types of parameters 'cb' and 'cb' are incompatible.
|
||||
Types of parameters 'x' and 'x' are incompatible.
|
||||
Type 'Animal' is not assignable to type 'Dog'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/strictFunctionTypesErrors.ts (31 errors) ====
|
||||
==== tests/cases/compiler/strictFunctionTypesErrors.ts (35 errors) ====
|
||||
export {}
|
||||
|
||||
|
||||
@ -337,4 +352,51 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(127,1): error TS2322: Type 'Cr
|
||||
!!! error TS2322: Type 'Crate<Animal>' is not assignable to type 'Crate<Dog>'.
|
||||
!!! error TS2322: Types of property 'item' are incompatible.
|
||||
!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'.
|
||||
|
||||
|
||||
// Verify that callback parameters are strictly checked
|
||||
|
||||
declare let fc1: (f: (x: Animal) => Animal) => void;
|
||||
declare let fc2: (f: (x: Dog) => Dog) => void;
|
||||
fc1 = fc2; // Error
|
||||
~~~
|
||||
!!! error TS2322: Type '(f: (x: Dog) => Dog) => void' is not assignable to type '(f: (x: Animal) => Animal) => void'.
|
||||
!!! error TS2322: Types of parameters 'f' and 'f' are incompatible.
|
||||
!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'.
|
||||
fc2 = fc1; // Error
|
||||
~~~
|
||||
!!! error TS2322: Type '(f: (x: Animal) => Animal) => void' is not assignable to type '(f: (x: Dog) => Dog) => void'.
|
||||
!!! error TS2322: Types of parameters 'f' and 'f' are incompatible.
|
||||
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
|
||||
!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'.
|
||||
|
||||
// Verify that callback parameters aren't loosely checked when types
|
||||
// originate in method declarations
|
||||
|
||||
namespace n1 {
|
||||
class Foo {
|
||||
static f1(x: Animal): Animal { throw "wat"; }
|
||||
static f2(x: Dog): Animal { throw "wat"; };
|
||||
}
|
||||
declare let f1: (cb: typeof Foo.f1) => void;
|
||||
declare let f2: (cb: typeof Foo.f2) => void;
|
||||
f1 = f2;
|
||||
f2 = f1; // Error
|
||||
~~
|
||||
!!! error TS2322: Type '(cb: (x: Animal) => Animal) => void' is not assignable to type '(cb: (x: Dog) => Animal) => void'.
|
||||
!!! error TS2322: Types of parameters 'cb' and 'cb' are incompatible.
|
||||
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
|
||||
!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'.
|
||||
}
|
||||
|
||||
namespace n2 {
|
||||
type BivariantHack<Input, Output> = { foo(x: Input): Output }["foo"];
|
||||
declare let f1: (cb: BivariantHack<Animal, Animal>) => void;
|
||||
declare let f2: (cb: BivariantHack<Dog, Animal>) => void;
|
||||
f1 = f2;
|
||||
f2 = f1; // Error
|
||||
~~
|
||||
!!! error TS2322: Type '(cb: (x: Animal) => Animal) => void' is not assignable to type '(cb: (x: Dog) => Animal) => void'.
|
||||
!!! error TS2322: Types of parameters 'cb' and 'cb' are incompatible.
|
||||
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
|
||||
!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'.
|
||||
}
|
||||
@ -126,7 +126,35 @@ declare let dogCrate: Crate<Dog>;
|
||||
|
||||
animalCrate = dogCrate; // Error
|
||||
dogCrate = animalCrate; // Error
|
||||
|
||||
|
||||
// Verify that callback parameters are strictly checked
|
||||
|
||||
declare let fc1: (f: (x: Animal) => Animal) => void;
|
||||
declare let fc2: (f: (x: Dog) => Dog) => void;
|
||||
fc1 = fc2; // Error
|
||||
fc2 = fc1; // Error
|
||||
|
||||
// Verify that callback parameters aren't loosely checked when types
|
||||
// originate in method declarations
|
||||
|
||||
namespace n1 {
|
||||
class Foo {
|
||||
static f1(x: Animal): Animal { throw "wat"; }
|
||||
static f2(x: Dog): Animal { throw "wat"; };
|
||||
}
|
||||
declare let f1: (cb: typeof Foo.f1) => void;
|
||||
declare let f2: (cb: typeof Foo.f2) => void;
|
||||
f1 = f2;
|
||||
f2 = f1; // Error
|
||||
}
|
||||
|
||||
namespace n2 {
|
||||
type BivariantHack<Input, Output> = { foo(x: Input): Output }["foo"];
|
||||
declare let f1: (cb: BivariantHack<Animal, Animal>) => void;
|
||||
declare let f2: (cb: BivariantHack<Dog, Animal>) => void;
|
||||
f1 = f2;
|
||||
f2 = f1; // Error
|
||||
}
|
||||
|
||||
//// [strictFunctionTypesErrors.js]
|
||||
"use strict";
|
||||
@ -186,3 +214,25 @@ dogComparer2 = animalComparer2; // Ok
|
||||
// Errors below should elaborate the reason for invariance
|
||||
animalCrate = dogCrate; // Error
|
||||
dogCrate = animalCrate; // Error
|
||||
fc1 = fc2; // Error
|
||||
fc2 = fc1; // Error
|
||||
// Verify that callback parameters aren't loosely checked when types
|
||||
// originate in method declarations
|
||||
var n1;
|
||||
(function (n1) {
|
||||
var Foo = /** @class */ (function () {
|
||||
function Foo() {
|
||||
}
|
||||
Foo.f1 = function (x) { throw "wat"; };
|
||||
Foo.f2 = function (x) { throw "wat"; };
|
||||
;
|
||||
return Foo;
|
||||
}());
|
||||
f1 = f2;
|
||||
f2 = f1; // Error
|
||||
})(n1 || (n1 = {}));
|
||||
var n2;
|
||||
(function (n2) {
|
||||
f1 = f2;
|
||||
f2 = f1; // Error
|
||||
})(n2 || (n2 = {}));
|
||||
|
||||
@ -400,3 +400,105 @@ dogCrate = animalCrate; // Error
|
||||
>dogCrate : Symbol(dogCrate, Decl(strictFunctionTypesErrors.ts, 121, 11))
|
||||
>animalCrate : Symbol(animalCrate, Decl(strictFunctionTypesErrors.ts, 120, 11))
|
||||
|
||||
// Verify that callback parameters are strictly checked
|
||||
|
||||
declare let fc1: (f: (x: Animal) => Animal) => void;
|
||||
>fc1 : Symbol(fc1, Decl(strictFunctionTypesErrors.ts, 130, 11))
|
||||
>f : Symbol(f, Decl(strictFunctionTypesErrors.ts, 130, 18))
|
||||
>x : Symbol(x, Decl(strictFunctionTypesErrors.ts, 130, 22))
|
||||
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
|
||||
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
|
||||
|
||||
declare let fc2: (f: (x: Dog) => Dog) => void;
|
||||
>fc2 : Symbol(fc2, Decl(strictFunctionTypesErrors.ts, 131, 11))
|
||||
>f : Symbol(f, Decl(strictFunctionTypesErrors.ts, 131, 18))
|
||||
>x : Symbol(x, Decl(strictFunctionTypesErrors.ts, 131, 22))
|
||||
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33))
|
||||
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33))
|
||||
|
||||
fc1 = fc2; // Error
|
||||
>fc1 : Symbol(fc1, Decl(strictFunctionTypesErrors.ts, 130, 11))
|
||||
>fc2 : Symbol(fc2, Decl(strictFunctionTypesErrors.ts, 131, 11))
|
||||
|
||||
fc2 = fc1; // Error
|
||||
>fc2 : Symbol(fc2, Decl(strictFunctionTypesErrors.ts, 131, 11))
|
||||
>fc1 : Symbol(fc1, Decl(strictFunctionTypesErrors.ts, 130, 11))
|
||||
|
||||
// Verify that callback parameters aren't loosely checked when types
|
||||
// originate in method declarations
|
||||
|
||||
namespace n1 {
|
||||
>n1 : Symbol(n1, Decl(strictFunctionTypesErrors.ts, 133, 10))
|
||||
|
||||
class Foo {
|
||||
>Foo : Symbol(Foo, Decl(strictFunctionTypesErrors.ts, 138, 14))
|
||||
|
||||
static f1(x: Animal): Animal { throw "wat"; }
|
||||
>f1 : Symbol(Foo.f1, Decl(strictFunctionTypesErrors.ts, 139, 15))
|
||||
>x : Symbol(x, Decl(strictFunctionTypesErrors.ts, 140, 18))
|
||||
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
|
||||
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
|
||||
|
||||
static f2(x: Dog): Animal { throw "wat"; };
|
||||
>f2 : Symbol(Foo.f2, Decl(strictFunctionTypesErrors.ts, 140, 53))
|
||||
>x : Symbol(x, Decl(strictFunctionTypesErrors.ts, 141, 18))
|
||||
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33))
|
||||
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
|
||||
}
|
||||
declare let f1: (cb: typeof Foo.f1) => void;
|
||||
>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 143, 15))
|
||||
>cb : Symbol(cb, Decl(strictFunctionTypesErrors.ts, 143, 21))
|
||||
>Foo.f1 : Symbol(Foo.f1, Decl(strictFunctionTypesErrors.ts, 139, 15))
|
||||
>Foo : Symbol(Foo, Decl(strictFunctionTypesErrors.ts, 138, 14))
|
||||
>f1 : Symbol(Foo.f1, Decl(strictFunctionTypesErrors.ts, 139, 15))
|
||||
|
||||
declare let f2: (cb: typeof Foo.f2) => void;
|
||||
>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 144, 15))
|
||||
>cb : Symbol(cb, Decl(strictFunctionTypesErrors.ts, 144, 21))
|
||||
>Foo.f2 : Symbol(Foo.f2, Decl(strictFunctionTypesErrors.ts, 140, 53))
|
||||
>Foo : Symbol(Foo, Decl(strictFunctionTypesErrors.ts, 138, 14))
|
||||
>f2 : Symbol(Foo.f2, Decl(strictFunctionTypesErrors.ts, 140, 53))
|
||||
|
||||
f1 = f2;
|
||||
>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 143, 15))
|
||||
>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 144, 15))
|
||||
|
||||
f2 = f1; // Error
|
||||
>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 144, 15))
|
||||
>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 143, 15))
|
||||
}
|
||||
|
||||
namespace n2 {
|
||||
>n2 : Symbol(n2, Decl(strictFunctionTypesErrors.ts, 147, 1))
|
||||
|
||||
type BivariantHack<Input, Output> = { foo(x: Input): Output }["foo"];
|
||||
>BivariantHack : Symbol(BivariantHack, Decl(strictFunctionTypesErrors.ts, 149, 14))
|
||||
>Input : Symbol(Input, Decl(strictFunctionTypesErrors.ts, 150, 23))
|
||||
>Output : Symbol(Output, Decl(strictFunctionTypesErrors.ts, 150, 29))
|
||||
>foo : Symbol(foo, Decl(strictFunctionTypesErrors.ts, 150, 41))
|
||||
>x : Symbol(x, Decl(strictFunctionTypesErrors.ts, 150, 46))
|
||||
>Input : Symbol(Input, Decl(strictFunctionTypesErrors.ts, 150, 23))
|
||||
>Output : Symbol(Output, Decl(strictFunctionTypesErrors.ts, 150, 29))
|
||||
|
||||
declare let f1: (cb: BivariantHack<Animal, Animal>) => void;
|
||||
>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 151, 15))
|
||||
>cb : Symbol(cb, Decl(strictFunctionTypesErrors.ts, 151, 21))
|
||||
>BivariantHack : Symbol(BivariantHack, Decl(strictFunctionTypesErrors.ts, 149, 14))
|
||||
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
|
||||
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
|
||||
|
||||
declare let f2: (cb: BivariantHack<Dog, Animal>) => void;
|
||||
>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 152, 15))
|
||||
>cb : Symbol(cb, Decl(strictFunctionTypesErrors.ts, 152, 21))
|
||||
>BivariantHack : Symbol(BivariantHack, Decl(strictFunctionTypesErrors.ts, 149, 14))
|
||||
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33))
|
||||
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
|
||||
|
||||
f1 = f2;
|
||||
>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 151, 15))
|
||||
>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 152, 15))
|
||||
|
||||
f2 = f1; // Error
|
||||
>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 152, 15))
|
||||
>f1 : Symbol(f1, Decl(strictFunctionTypesErrors.ts, 151, 15))
|
||||
}
|
||||
|
||||
@ -454,3 +454,113 @@ dogCrate = animalCrate; // Error
|
||||
>dogCrate : Crate<Dog>
|
||||
>animalCrate : Crate<Animal>
|
||||
|
||||
// Verify that callback parameters are strictly checked
|
||||
|
||||
declare let fc1: (f: (x: Animal) => Animal) => void;
|
||||
>fc1 : (f: (x: Animal) => Animal) => void
|
||||
>f : (x: Animal) => Animal
|
||||
>x : Animal
|
||||
>Animal : Animal
|
||||
>Animal : Animal
|
||||
|
||||
declare let fc2: (f: (x: Dog) => Dog) => void;
|
||||
>fc2 : (f: (x: Dog) => Dog) => void
|
||||
>f : (x: Dog) => Dog
|
||||
>x : Dog
|
||||
>Dog : Dog
|
||||
>Dog : Dog
|
||||
|
||||
fc1 = fc2; // Error
|
||||
>fc1 = fc2 : (f: (x: Dog) => Dog) => void
|
||||
>fc1 : (f: (x: Animal) => Animal) => void
|
||||
>fc2 : (f: (x: Dog) => Dog) => void
|
||||
|
||||
fc2 = fc1; // Error
|
||||
>fc2 = fc1 : (f: (x: Animal) => Animal) => void
|
||||
>fc2 : (f: (x: Dog) => Dog) => void
|
||||
>fc1 : (f: (x: Animal) => Animal) => void
|
||||
|
||||
// Verify that callback parameters aren't loosely checked when types
|
||||
// originate in method declarations
|
||||
|
||||
namespace n1 {
|
||||
>n1 : typeof n1
|
||||
|
||||
class Foo {
|
||||
>Foo : Foo
|
||||
|
||||
static f1(x: Animal): Animal { throw "wat"; }
|
||||
>f1 : (x: Animal) => Animal
|
||||
>x : Animal
|
||||
>Animal : Animal
|
||||
>Animal : Animal
|
||||
>"wat" : "wat"
|
||||
|
||||
static f2(x: Dog): Animal { throw "wat"; };
|
||||
>f2 : (x: Dog) => Animal
|
||||
>x : Dog
|
||||
>Dog : Dog
|
||||
>Animal : Animal
|
||||
>"wat" : "wat"
|
||||
}
|
||||
declare let f1: (cb: typeof Foo.f1) => void;
|
||||
>f1 : (cb: (x: Animal) => Animal) => void
|
||||
>cb : (x: Animal) => Animal
|
||||
>Foo.f1 : (x: Animal) => Animal
|
||||
>Foo : typeof Foo
|
||||
>f1 : (x: Animal) => Animal
|
||||
|
||||
declare let f2: (cb: typeof Foo.f2) => void;
|
||||
>f2 : (cb: (x: Dog) => Animal) => void
|
||||
>cb : (x: Dog) => Animal
|
||||
>Foo.f2 : (x: Dog) => Animal
|
||||
>Foo : typeof Foo
|
||||
>f2 : (x: Dog) => Animal
|
||||
|
||||
f1 = f2;
|
||||
>f1 = f2 : (cb: (x: Dog) => Animal) => void
|
||||
>f1 : (cb: (x: Animal) => Animal) => void
|
||||
>f2 : (cb: (x: Dog) => Animal) => void
|
||||
|
||||
f2 = f1; // Error
|
||||
>f2 = f1 : (cb: (x: Animal) => Animal) => void
|
||||
>f2 : (cb: (x: Dog) => Animal) => void
|
||||
>f1 : (cb: (x: Animal) => Animal) => void
|
||||
}
|
||||
|
||||
namespace n2 {
|
||||
>n2 : typeof n2
|
||||
|
||||
type BivariantHack<Input, Output> = { foo(x: Input): Output }["foo"];
|
||||
>BivariantHack : (x: Input) => Output
|
||||
>Input : Input
|
||||
>Output : Output
|
||||
>foo : (x: Input) => Output
|
||||
>x : Input
|
||||
>Input : Input
|
||||
>Output : Output
|
||||
|
||||
declare let f1: (cb: BivariantHack<Animal, Animal>) => void;
|
||||
>f1 : (cb: (x: Animal) => Animal) => void
|
||||
>cb : (x: Animal) => Animal
|
||||
>BivariantHack : (x: Input) => Output
|
||||
>Animal : Animal
|
||||
>Animal : Animal
|
||||
|
||||
declare let f2: (cb: BivariantHack<Dog, Animal>) => void;
|
||||
>f2 : (cb: (x: Dog) => Animal) => void
|
||||
>cb : (x: Dog) => Animal
|
||||
>BivariantHack : (x: Input) => Output
|
||||
>Dog : Dog
|
||||
>Animal : Animal
|
||||
|
||||
f1 = f2;
|
||||
>f1 = f2 : (cb: (x: Dog) => Animal) => void
|
||||
>f1 : (cb: (x: Animal) => Animal) => void
|
||||
>f2 : (cb: (x: Dog) => Animal) => void
|
||||
|
||||
f2 = f1; // Error
|
||||
>f2 = f1 : (cb: (x: Animal) => Animal) => void
|
||||
>f2 : (cb: (x: Dog) => Animal) => void
|
||||
>f1 : (cb: (x: Animal) => Animal) => void
|
||||
}
|
||||
|
||||
@ -126,3 +126,32 @@ declare let dogCrate: Crate<Dog>;
|
||||
|
||||
animalCrate = dogCrate; // Error
|
||||
dogCrate = animalCrate; // Error
|
||||
|
||||
// Verify that callback parameters are strictly checked
|
||||
|
||||
declare let fc1: (f: (x: Animal) => Animal) => void;
|
||||
declare let fc2: (f: (x: Dog) => Dog) => void;
|
||||
fc1 = fc2; // Error
|
||||
fc2 = fc1; // Error
|
||||
|
||||
// Verify that callback parameters aren't loosely checked when types
|
||||
// originate in method declarations
|
||||
|
||||
namespace n1 {
|
||||
class Foo {
|
||||
static f1(x: Animal): Animal { throw "wat"; }
|
||||
static f2(x: Dog): Animal { throw "wat"; };
|
||||
}
|
||||
declare let f1: (cb: typeof Foo.f1) => void;
|
||||
declare let f2: (cb: typeof Foo.f2) => void;
|
||||
f1 = f2;
|
||||
f2 = f1; // Error
|
||||
}
|
||||
|
||||
namespace n2 {
|
||||
type BivariantHack<Input, Output> = { foo(x: Input): Output }["foo"];
|
||||
declare let f1: (cb: BivariantHack<Animal, Animal>) => void;
|
||||
declare let f2: (cb: BivariantHack<Dog, Animal>) => void;
|
||||
f1 = f2;
|
||||
f2 = f1; // Error
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user