Add tests

This commit is contained in:
Anders Hejlsberg
2016-06-08 11:41:44 -07:00
parent ea1bdff096
commit a57ee29ff7
4 changed files with 868 additions and 0 deletions

View File

@@ -0,0 +1,181 @@
//// [typeGuardIntersectionTypes.ts]
interface X {
x: string;
}
interface Y {
y: string;
}
interface Z {
z: string;
}
declare function isX(obj: any): obj is X;
declare function isY(obj: any): obj is Y;
declare function isZ(obj: any): obj is Z;
function f1(obj: Object) {
if (isX(obj) || isY(obj) || isZ(obj)) {
obj;
}
if (isX(obj) && isY(obj) && isZ(obj)) {
obj;
}
}
// Repro from #8911
// two interfaces
interface A {
a: string;
}
interface B {
b: string;
}
// a type guard for B
function isB(toTest: any): toTest is B {
return toTest && toTest.b;
}
// a function that turns an A into an A & B
function union(a: A): A & B | null {
if (isB(a)) {
return a;
} else {
return null;
}
}
// Repro from #9011
declare function log(s: string): void;
// Supported beast features
interface Beast { wings?: boolean; legs?: number }
interface Legged { legs: number; }
interface Winged { wings: boolean; }
// Beast feature detection via user-defined type guards
function hasLegs(x: Beast): x is Legged { return x && typeof x.legs === 'number'; }
function hasWings(x: Beast): x is Winged { return x && !!x.wings; }
// Function to identify a given beast by detecting its features
function identifyBeast(beast: Beast) {
// All beasts with legs
if (hasLegs(beast)) {
// All winged beasts with legs
if (hasWings(beast)) {
if (beast.legs === 4) { // ERROR TS2339: Property 'legs' does not exist on type 'Winged'.
log(`pegasus - 4 legs, wings`);
}
else if (beast.legs === 2) { // ERROR TS2339...
log(`bird - 2 legs, wings`);
}
else {
log(`unknown - ${beast.legs} legs, wings`); // ERROR TS2339...
}
}
// All non-winged beasts with legs
else {
log(`manbearpig - ${beast.legs} legs, no wings`);
}
}
// All beasts without legs
else {
if (hasWings(beast)) {
log(`quetzalcoatl - no legs, wings`)
}
else {
log(`snake - no legs, no wings`)
}
}
}
function beastFoo(beast: Object) {
if (hasWings(beast) && hasLegs(beast)) {
beast // beast is Legged
// ideally, beast would be Winged && Legged here...
}
else {
beast
}
if (hasLegs(beast) && hasWings(beast)) {
beast // beast is Winged
// ideally, beast would be Legged && Winged here...
}
}
//// [typeGuardIntersectionTypes.js]
function f1(obj) {
if (isX(obj) || isY(obj) || isZ(obj)) {
obj;
}
if (isX(obj) && isY(obj) && isZ(obj)) {
obj;
}
}
// a type guard for B
function isB(toTest) {
return toTest && toTest.b;
}
// a function that turns an A into an A & B
function union(a) {
if (isB(a)) {
return a;
}
else {
return null;
}
}
// Beast feature detection via user-defined type guards
function hasLegs(x) { return x && typeof x.legs === 'number'; }
function hasWings(x) { return x && !!x.wings; }
// Function to identify a given beast by detecting its features
function identifyBeast(beast) {
// All beasts with legs
if (hasLegs(beast)) {
// All winged beasts with legs
if (hasWings(beast)) {
if (beast.legs === 4) {
log("pegasus - 4 legs, wings");
}
else if (beast.legs === 2) {
log("bird - 2 legs, wings");
}
else {
log("unknown - " + beast.legs + " legs, wings"); // ERROR TS2339...
}
}
else {
log("manbearpig - " + beast.legs + " legs, no wings");
}
}
else {
if (hasWings(beast)) {
log("quetzalcoatl - no legs, wings");
}
else {
log("snake - no legs, no wings");
}
}
}
function beastFoo(beast) {
if (hasWings(beast) && hasLegs(beast)) {
beast; // beast is Legged
}
else {
beast;
}
if (hasLegs(beast) && hasWings(beast)) {
beast; // beast is Winged
}
}

View File

@@ -0,0 +1,262 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardIntersectionTypes.ts ===
interface X {
>X : Symbol(X, Decl(typeGuardIntersectionTypes.ts, 0, 0))
x: string;
>x : Symbol(X.x, Decl(typeGuardIntersectionTypes.ts, 1, 13))
}
interface Y {
>Y : Symbol(Y, Decl(typeGuardIntersectionTypes.ts, 3, 1))
y: string;
>y : Symbol(Y.y, Decl(typeGuardIntersectionTypes.ts, 5, 13))
}
interface Z {
>Z : Symbol(Z, Decl(typeGuardIntersectionTypes.ts, 7, 1))
z: string;
>z : Symbol(Z.z, Decl(typeGuardIntersectionTypes.ts, 9, 13))
}
declare function isX(obj: any): obj is X;
>isX : Symbol(isX, Decl(typeGuardIntersectionTypes.ts, 11, 1))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 13, 21))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 13, 21))
>X : Symbol(X, Decl(typeGuardIntersectionTypes.ts, 0, 0))
declare function isY(obj: any): obj is Y;
>isY : Symbol(isY, Decl(typeGuardIntersectionTypes.ts, 13, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 14, 21))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 14, 21))
>Y : Symbol(Y, Decl(typeGuardIntersectionTypes.ts, 3, 1))
declare function isZ(obj: any): obj is Z;
>isZ : Symbol(isZ, Decl(typeGuardIntersectionTypes.ts, 14, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 15, 21))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 15, 21))
>Z : Symbol(Z, Decl(typeGuardIntersectionTypes.ts, 7, 1))
function f1(obj: Object) {
>f1 : Symbol(f1, Decl(typeGuardIntersectionTypes.ts, 15, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
if (isX(obj) || isY(obj) || isZ(obj)) {
>isX : Symbol(isX, Decl(typeGuardIntersectionTypes.ts, 11, 1))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
>isY : Symbol(isY, Decl(typeGuardIntersectionTypes.ts, 13, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
>isZ : Symbol(isZ, Decl(typeGuardIntersectionTypes.ts, 14, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
obj;
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
}
if (isX(obj) && isY(obj) && isZ(obj)) {
>isX : Symbol(isX, Decl(typeGuardIntersectionTypes.ts, 11, 1))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
>isY : Symbol(isY, Decl(typeGuardIntersectionTypes.ts, 13, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
>isZ : Symbol(isZ, Decl(typeGuardIntersectionTypes.ts, 14, 41))
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
obj;
>obj : Symbol(obj, Decl(typeGuardIntersectionTypes.ts, 17, 12))
}
}
// Repro from #8911
// two interfaces
interface A {
>A : Symbol(A, Decl(typeGuardIntersectionTypes.ts, 24, 1))
a: string;
>a : Symbol(A.a, Decl(typeGuardIntersectionTypes.ts, 29, 13))
}
interface B {
>B : Symbol(B, Decl(typeGuardIntersectionTypes.ts, 31, 1))
b: string;
>b : Symbol(B.b, Decl(typeGuardIntersectionTypes.ts, 33, 13))
}
// a type guard for B
function isB(toTest: any): toTest is B {
>isB : Symbol(isB, Decl(typeGuardIntersectionTypes.ts, 35, 1))
>toTest : Symbol(toTest, Decl(typeGuardIntersectionTypes.ts, 38, 13))
>toTest : Symbol(toTest, Decl(typeGuardIntersectionTypes.ts, 38, 13))
>B : Symbol(B, Decl(typeGuardIntersectionTypes.ts, 31, 1))
return toTest && toTest.b;
>toTest : Symbol(toTest, Decl(typeGuardIntersectionTypes.ts, 38, 13))
>toTest : Symbol(toTest, Decl(typeGuardIntersectionTypes.ts, 38, 13))
}
// a function that turns an A into an A & B
function union(a: A): A & B | null {
>union : Symbol(union, Decl(typeGuardIntersectionTypes.ts, 40, 1))
>a : Symbol(a, Decl(typeGuardIntersectionTypes.ts, 43, 15))
>A : Symbol(A, Decl(typeGuardIntersectionTypes.ts, 24, 1))
>A : Symbol(A, Decl(typeGuardIntersectionTypes.ts, 24, 1))
>B : Symbol(B, Decl(typeGuardIntersectionTypes.ts, 31, 1))
if (isB(a)) {
>isB : Symbol(isB, Decl(typeGuardIntersectionTypes.ts, 35, 1))
>a : Symbol(a, Decl(typeGuardIntersectionTypes.ts, 43, 15))
return a;
>a : Symbol(a, Decl(typeGuardIntersectionTypes.ts, 43, 15))
} else {
return null;
}
}
// Repro from #9011
declare function log(s: string): void;
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
>s : Symbol(s, Decl(typeGuardIntersectionTypes.ts, 53, 21))
// Supported beast features
interface Beast { wings?: boolean; legs?: number }
>Beast : Symbol(Beast, Decl(typeGuardIntersectionTypes.ts, 53, 38))
>wings : Symbol(Beast.wings, Decl(typeGuardIntersectionTypes.ts, 56, 21))
>legs : Symbol(Beast.legs, Decl(typeGuardIntersectionTypes.ts, 56, 38))
interface Legged { legs: number; }
>Legged : Symbol(Legged, Decl(typeGuardIntersectionTypes.ts, 56, 54))
>legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
interface Winged { wings: boolean; }
>Winged : Symbol(Winged, Decl(typeGuardIntersectionTypes.ts, 57, 37))
>wings : Symbol(Winged.wings, Decl(typeGuardIntersectionTypes.ts, 58, 21))
// Beast feature detection via user-defined type guards
function hasLegs(x: Beast): x is Legged { return x && typeof x.legs === 'number'; }
>hasLegs : Symbol(hasLegs, Decl(typeGuardIntersectionTypes.ts, 58, 39))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 61, 17))
>Beast : Symbol(Beast, Decl(typeGuardIntersectionTypes.ts, 53, 38))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 61, 17))
>Legged : Symbol(Legged, Decl(typeGuardIntersectionTypes.ts, 56, 54))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 61, 17))
>x.legs : Symbol(Beast.legs, Decl(typeGuardIntersectionTypes.ts, 56, 38))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 61, 17))
>legs : Symbol(Beast.legs, Decl(typeGuardIntersectionTypes.ts, 56, 38))
function hasWings(x: Beast): x is Winged { return x && !!x.wings; }
>hasWings : Symbol(hasWings, Decl(typeGuardIntersectionTypes.ts, 61, 83))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 62, 18))
>Beast : Symbol(Beast, Decl(typeGuardIntersectionTypes.ts, 53, 38))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 62, 18))
>Winged : Symbol(Winged, Decl(typeGuardIntersectionTypes.ts, 57, 37))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 62, 18))
>x.wings : Symbol(Beast.wings, Decl(typeGuardIntersectionTypes.ts, 56, 21))
>x : Symbol(x, Decl(typeGuardIntersectionTypes.ts, 62, 18))
>wings : Symbol(Beast.wings, Decl(typeGuardIntersectionTypes.ts, 56, 21))
// Function to identify a given beast by detecting its features
function identifyBeast(beast: Beast) {
>identifyBeast : Symbol(identifyBeast, Decl(typeGuardIntersectionTypes.ts, 62, 67))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
>Beast : Symbol(Beast, Decl(typeGuardIntersectionTypes.ts, 53, 38))
// All beasts with legs
if (hasLegs(beast)) {
>hasLegs : Symbol(hasLegs, Decl(typeGuardIntersectionTypes.ts, 58, 39))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
// All winged beasts with legs
if (hasWings(beast)) {
>hasWings : Symbol(hasWings, Decl(typeGuardIntersectionTypes.ts, 61, 83))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
if (beast.legs === 4) { // ERROR TS2339: Property 'legs' does not exist on type 'Winged'.
>beast.legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
>legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
log(`pegasus - 4 legs, wings`);
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
}
else if (beast.legs === 2) { // ERROR TS2339...
>beast.legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
>legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
log(`bird - 2 legs, wings`);
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
}
else {
log(`unknown - ${beast.legs} legs, wings`); // ERROR TS2339...
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
>beast.legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
>legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
}
}
// All non-winged beasts with legs
else {
log(`manbearpig - ${beast.legs} legs, no wings`);
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
>beast.legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
>legs : Symbol(Legged.legs, Decl(typeGuardIntersectionTypes.ts, 57, 21))
}
}
// All beasts without legs
else {
if (hasWings(beast)) {
>hasWings : Symbol(hasWings, Decl(typeGuardIntersectionTypes.ts, 61, 83))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 65, 23))
log(`quetzalcoatl - no legs, wings`)
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
}
else {
log(`snake - no legs, no wings`)
>log : Symbol(log, Decl(typeGuardIntersectionTypes.ts, 49, 1))
}
}
}
function beastFoo(beast: Object) {
>beastFoo : Symbol(beastFoo, Decl(typeGuardIntersectionTypes.ts, 98, 1))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
if (hasWings(beast) && hasLegs(beast)) {
>hasWings : Symbol(hasWings, Decl(typeGuardIntersectionTypes.ts, 61, 83))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
>hasLegs : Symbol(hasLegs, Decl(typeGuardIntersectionTypes.ts, 58, 39))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
beast // beast is Legged
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
// ideally, beast would be Winged && Legged here...
}
else {
beast
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
}
if (hasLegs(beast) && hasWings(beast)) {
>hasLegs : Symbol(hasLegs, Decl(typeGuardIntersectionTypes.ts, 58, 39))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
>hasWings : Symbol(hasWings, Decl(typeGuardIntersectionTypes.ts, 61, 83))
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
beast // beast is Winged
>beast : Symbol(beast, Decl(typeGuardIntersectionTypes.ts, 100, 18))
// ideally, beast would be Legged && Winged here...
}
}

View File

@@ -0,0 +1,310 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardIntersectionTypes.ts ===
interface X {
>X : X
x: string;
>x : string
}
interface Y {
>Y : Y
y: string;
>y : string
}
interface Z {
>Z : Z
z: string;
>z : string
}
declare function isX(obj: any): obj is X;
>isX : (obj: any) => obj is X
>obj : any
>obj : any
>X : X
declare function isY(obj: any): obj is Y;
>isY : (obj: any) => obj is Y
>obj : any
>obj : any
>Y : Y
declare function isZ(obj: any): obj is Z;
>isZ : (obj: any) => obj is Z
>obj : any
>obj : any
>Z : Z
function f1(obj: Object) {
>f1 : (obj: Object) => void
>obj : Object
>Object : Object
if (isX(obj) || isY(obj) || isZ(obj)) {
>isX(obj) || isY(obj) || isZ(obj) : boolean
>isX(obj) || isY(obj) : boolean
>isX(obj) : boolean
>isX : (obj: any) => obj is X
>obj : Object
>isY(obj) : boolean
>isY : (obj: any) => obj is Y
>obj : Object
>isZ(obj) : boolean
>isZ : (obj: any) => obj is Z
>obj : Object
obj;
>obj : X | Y | Z
}
if (isX(obj) && isY(obj) && isZ(obj)) {
>isX(obj) && isY(obj) && isZ(obj) : boolean
>isX(obj) && isY(obj) : boolean
>isX(obj) : boolean
>isX : (obj: any) => obj is X
>obj : Object
>isY(obj) : boolean
>isY : (obj: any) => obj is Y
>obj : X
>isZ(obj) : boolean
>isZ : (obj: any) => obj is Z
>obj : X & Y
obj;
>obj : X & Y & Z
}
}
// Repro from #8911
// two interfaces
interface A {
>A : A
a: string;
>a : string
}
interface B {
>B : B
b: string;
>b : string
}
// a type guard for B
function isB(toTest: any): toTest is B {
>isB : (toTest: any) => toTest is B
>toTest : any
>toTest : any
>B : B
return toTest && toTest.b;
>toTest && toTest.b : any
>toTest : any
>toTest.b : any
>toTest : any
>b : any
}
// a function that turns an A into an A & B
function union(a: A): A & B | null {
>union : (a: A) => (A & B) | null
>a : A
>A : A
>A : A
>B : B
>null : null
if (isB(a)) {
>isB(a) : boolean
>isB : (toTest: any) => toTest is B
>a : A
return a;
>a : A & B
} else {
return null;
>null : null
}
}
// Repro from #9011
declare function log(s: string): void;
>log : (s: string) => void
>s : string
// Supported beast features
interface Beast { wings?: boolean; legs?: number }
>Beast : Beast
>wings : boolean | undefined
>legs : number | undefined
interface Legged { legs: number; }
>Legged : Legged
>legs : number
interface Winged { wings: boolean; }
>Winged : Winged
>wings : boolean
// Beast feature detection via user-defined type guards
function hasLegs(x: Beast): x is Legged { return x && typeof x.legs === 'number'; }
>hasLegs : (x: Beast) => x is Legged
>x : Beast
>Beast : Beast
>x : any
>Legged : Legged
>x && typeof x.legs === 'number' : boolean
>x : Beast
>typeof x.legs === 'number' : boolean
>typeof x.legs : string
>x.legs : number | undefined
>x : Beast
>legs : number | undefined
>'number' : string
function hasWings(x: Beast): x is Winged { return x && !!x.wings; }
>hasWings : (x: Beast) => x is Winged
>x : Beast
>Beast : Beast
>x : any
>Winged : Winged
>x && !!x.wings : boolean
>x : Beast
>!!x.wings : boolean
>!x.wings : boolean
>x.wings : boolean | undefined
>x : Beast
>wings : boolean | undefined
// Function to identify a given beast by detecting its features
function identifyBeast(beast: Beast) {
>identifyBeast : (beast: Beast) => void
>beast : Beast
>Beast : Beast
// All beasts with legs
if (hasLegs(beast)) {
>hasLegs(beast) : boolean
>hasLegs : (x: Beast) => x is Legged
>beast : Beast
// All winged beasts with legs
if (hasWings(beast)) {
>hasWings(beast) : boolean
>hasWings : (x: Beast) => x is Winged
>beast : Legged
if (beast.legs === 4) { // ERROR TS2339: Property 'legs' does not exist on type 'Winged'.
>beast.legs === 4 : boolean
>beast.legs : number
>beast : Legged & Winged
>legs : number
>4 : number
log(`pegasus - 4 legs, wings`);
>log(`pegasus - 4 legs, wings`) : void
>log : (s: string) => void
>`pegasus - 4 legs, wings` : string
}
else if (beast.legs === 2) { // ERROR TS2339...
>beast.legs === 2 : boolean
>beast.legs : number
>beast : Legged & Winged
>legs : number
>2 : number
log(`bird - 2 legs, wings`);
>log(`bird - 2 legs, wings`) : void
>log : (s: string) => void
>`bird - 2 legs, wings` : string
}
else {
log(`unknown - ${beast.legs} legs, wings`); // ERROR TS2339...
>log(`unknown - ${beast.legs} legs, wings`) : void
>log : (s: string) => void
>`unknown - ${beast.legs} legs, wings` : string
>beast.legs : number
>beast : Legged & Winged
>legs : number
}
}
// All non-winged beasts with legs
else {
log(`manbearpig - ${beast.legs} legs, no wings`);
>log(`manbearpig - ${beast.legs} legs, no wings`) : void
>log : (s: string) => void
>`manbearpig - ${beast.legs} legs, no wings` : string
>beast.legs : number
>beast : Legged
>legs : number
}
}
// All beasts without legs
else {
if (hasWings(beast)) {
>hasWings(beast) : boolean
>hasWings : (x: Beast) => x is Winged
>beast : Beast
log(`quetzalcoatl - no legs, wings`)
>log(`quetzalcoatl - no legs, wings`) : void
>log : (s: string) => void
>`quetzalcoatl - no legs, wings` : string
}
else {
log(`snake - no legs, no wings`)
>log(`snake - no legs, no wings`) : void
>log : (s: string) => void
>`snake - no legs, no wings` : string
}
}
}
function beastFoo(beast: Object) {
>beastFoo : (beast: Object) => void
>beast : Object
>Object : Object
if (hasWings(beast) && hasLegs(beast)) {
>hasWings(beast) && hasLegs(beast) : boolean
>hasWings(beast) : boolean
>hasWings : (x: Beast) => x is Winged
>beast : Object
>hasLegs(beast) : boolean
>hasLegs : (x: Beast) => x is Legged
>beast : Winged
beast // beast is Legged
>beast : Winged & Legged
// ideally, beast would be Winged && Legged here...
}
else {
beast
>beast : Object
}
if (hasLegs(beast) && hasWings(beast)) {
>hasLegs(beast) && hasWings(beast) : boolean
>hasLegs(beast) : boolean
>hasLegs : (x: Beast) => x is Legged
>beast : Object
>hasWings(beast) : boolean
>hasWings : (x: Beast) => x is Winged
>beast : Legged
beast // beast is Winged
>beast : Legged & Winged
// ideally, beast would be Legged && Winged here...
}
}

View File

@@ -0,0 +1,115 @@
// @strictNullChecks: true
interface X {
x: string;
}
interface Y {
y: string;
}
interface Z {
z: string;
}
declare function isX(obj: any): obj is X;
declare function isY(obj: any): obj is Y;
declare function isZ(obj: any): obj is Z;
function f1(obj: Object) {
if (isX(obj) || isY(obj) || isZ(obj)) {
obj;
}
if (isX(obj) && isY(obj) && isZ(obj)) {
obj;
}
}
// Repro from #8911
// two interfaces
interface A {
a: string;
}
interface B {
b: string;
}
// a type guard for B
function isB(toTest: any): toTest is B {
return toTest && toTest.b;
}
// a function that turns an A into an A & B
function union(a: A): A & B | null {
if (isB(a)) {
return a;
} else {
return null;
}
}
// Repro from #9011
declare function log(s: string): void;
// Supported beast features
interface Beast { wings?: boolean; legs?: number }
interface Legged { legs: number; }
interface Winged { wings: boolean; }
// Beast feature detection via user-defined type guards
function hasLegs(x: Beast): x is Legged { return x && typeof x.legs === 'number'; }
function hasWings(x: Beast): x is Winged { return x && !!x.wings; }
// Function to identify a given beast by detecting its features
function identifyBeast(beast: Beast) {
// All beasts with legs
if (hasLegs(beast)) {
// All winged beasts with legs
if (hasWings(beast)) {
if (beast.legs === 4) { // ERROR TS2339: Property 'legs' does not exist on type 'Winged'.
log(`pegasus - 4 legs, wings`);
}
else if (beast.legs === 2) { // ERROR TS2339...
log(`bird - 2 legs, wings`);
}
else {
log(`unknown - ${beast.legs} legs, wings`); // ERROR TS2339...
}
}
// All non-winged beasts with legs
else {
log(`manbearpig - ${beast.legs} legs, no wings`);
}
}
// All beasts without legs
else {
if (hasWings(beast)) {
log(`quetzalcoatl - no legs, wings`)
}
else {
log(`snake - no legs, no wings`)
}
}
}
function beastFoo(beast: Object) {
if (hasWings(beast) && hasLegs(beast)) {
beast // beast is Legged
// ideally, beast would be Winged && Legged here...
}
else {
beast
}
if (hasLegs(beast) && hasWings(beast)) {
beast // beast is Winged
// ideally, beast would be Legged && Winged here...
}
}