1/* 2* Copyright (c) Microsoft Corporation. All rights reserved. 3* Copyright (c) 2023 Huawei Device Co., Ltd. 4* Licensed under the Apache License, Version 2.0 (the "License"); 5* you may not use this file except in compliance with the License. 6* You may obtain a copy of the License at 7* 8* http://www.apache.org/licenses/LICENSE-2.0 9* 10* Unless required by applicable law or agreed to in writing, software 11* distributed under the License is distributed on an "AS IS" BASIS, 12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13* See the License for the specific language governing permissions and 14* limitations under the License. 15* 16* This file has been modified by Huawei to verify type inference by adding verification statements. 17*/ 18 19// === tests/cases/conformance/expressions/typeGuards/typeGuardIntersectionTypes.ts === 20declare function AssertType(value:any, type:string):void; 21interface X { 22 x: string; 23} 24 25interface Y { 26 y: string; 27} 28 29interface Z { 30 z: string; 31} 32 33declare function isX(obj: any): obj is X; 34declare function isY(obj: any): obj is Y; 35declare function isZ(obj: any): obj is Z; 36 37function f1(obj: Object) { 38 if (isX(obj) || isY(obj) || isZ(obj)) { 39AssertType(isX(obj) || isY(obj) || isZ(obj), "boolean"); 40AssertType(isX(obj) || isY(obj), "boolean"); 41AssertType(isX(obj), "boolean"); 42AssertType(isX, "(any) => obj is X"); 43AssertType(obj, "Object"); 44AssertType(isY(obj), "boolean"); 45AssertType(isY, "(any) => obj is Y"); 46AssertType(obj, "Object"); 47AssertType(isZ(obj), "boolean"); 48AssertType(isZ, "(any) => obj is Z"); 49AssertType(obj, "Object"); 50 51 obj; 52AssertType(obj, "union"); 53 } 54 if (isX(obj) && isY(obj) && isZ(obj)) { 55AssertType(isX(obj) && isY(obj) && isZ(obj), "boolean"); 56AssertType(isX(obj) && isY(obj), "boolean"); 57AssertType(isX(obj), "boolean"); 58AssertType(isX, "(any) => obj is X"); 59AssertType(obj, "Object"); 60AssertType(isY(obj), "boolean"); 61AssertType(isY, "(any) => obj is Y"); 62AssertType(obj, "X"); 63AssertType(isZ(obj), "boolean"); 64AssertType(isZ, "(any) => obj is Z"); 65AssertType(obj, "X & Y"); 66 67 obj; 68AssertType(obj, "X & Y & Z"); 69 } 70} 71 72// Repro from #8911 73 74// two interfaces 75interface A { 76 a: string; 77} 78 79interface B { 80 b: string; 81} 82 83// a type guard for B 84function isB(toTest: any): toTest is B { 85AssertType(toTest && toTest.b, "any"); 86AssertType(toTest, "any"); 87AssertType(toTest.b, "any"); 88 return toTest && toTest.b; 89} 90 91// a function that turns an A into an A & B 92function union(a: A): A & B | null { 93 if (isB(a)) { 94AssertType(isB(a), "boolean"); 95AssertType(isB, "(any) => toTest is B"); 96AssertType(a, "A"); 97 98AssertType(a, "A & B"); 99 return a; 100 101 } else { 102AssertType(null, "null"); 103 return null; 104 } 105} 106 107// Repro from #9016 108 109declare function log(s: string): void; 110 111// Supported beast features 112interface Beast { wings?: boolean; legs?: number } 113interface Legged { legs: number; } 114interface Winged { wings: boolean; } 115 116// Beast feature detection via user-defined type guards 117function hasLegs(x: Beast): x is Legged { 118AssertType(x && typeof x.legs === 'number', "boolean"); 119return x && typeof x.legs === 'number'; 120 121AssertType(x, "Beast"); 122 123AssertType(typeof x.legs === 'number', "boolean"); 124 125AssertType(typeof x.legs, "union"); 126 127AssertType(x.legs, "union"); 128 129AssertType('number', "string"); 130} 131 132function hasWings(x: Beast): x is Winged { 133AssertType(x && !!x.wings, "boolean"); 134return x && !!x.wings; 135 136AssertType(x, "Beast"); 137 138AssertType(!!x.wings, "boolean"); 139 140AssertType(!x.wings, "boolean"); 141 142AssertType(x.wings, "union"); 143} 144 145// Function to identify a given beast by detecting its features 146function identifyBeast(beast: Beast) { 147 148 // All beasts with legs 149 if (hasLegs(beast)) { 150AssertType(hasLegs(beast), "boolean"); 151AssertType(hasLegs, "(Beast) => x is Legged"); 152AssertType(beast, "Beast"); 153 154 // All winged beasts with legs 155 if (hasWings(beast)) { 156AssertType(hasWings(beast), "boolean"); 157AssertType(hasWings, "(Beast) => x is Winged"); 158AssertType(beast, "Legged"); 159 160 if (beast.legs === 4) { 161AssertType(beast.legs === 4, "boolean"); 162AssertType(beast.legs, "number"); 163AssertType(4, "int"); 164 165 log(`pegasus - 4 legs, wings`); 166AssertType(log(`pegasus - 4 legs, wings`), "void"); 167AssertType(log, "(string) => void"); 168AssertType(`pegasus - 4 legs, wings`, "string"); 169 } 170 else if (beast.legs === 2) { 171AssertType(beast.legs === 2, "boolean"); 172AssertType(beast.legs, "number"); 173AssertType(2, "int"); 174 175 log(`bird - 2 legs, wings`); 176AssertType(log(`bird - 2 legs, wings`), "void"); 177AssertType(log, "(string) => void"); 178AssertType(`bird - 2 legs, wings`, "string"); 179 } 180 else { 181 log(`unknown - ${beast.legs} legs, wings`); 182AssertType(log(`unknown - ${beast.legs} legs, wings`), "void"); 183AssertType(log, "(string) => void"); 184AssertType(`unknown - ${beast.legs} legs, wings`, "string"); 185AssertType(beast.legs, "number"); 186 } 187 } 188 189 // All non-winged beasts with legs 190 else { 191 log(`manbearpig - ${beast.legs} legs, no wings`); 192AssertType(log(`manbearpig - ${beast.legs} legs, no wings`), "void"); 193AssertType(log, "(string) => void"); 194AssertType(`manbearpig - ${beast.legs} legs, no wings`, "string"); 195AssertType(beast.legs, "number"); 196 } 197 } 198 199 // All beasts without legs 200 else { 201 if (hasWings(beast)) { 202AssertType(hasWings(beast), "boolean"); 203AssertType(hasWings, "(Beast) => x is Winged"); 204AssertType(beast, "Beast"); 205 206 log(`quetzalcoatl - no legs, wings`) 207AssertType(log(`quetzalcoatl - no legs, wings`), "void"); 208AssertType(log, "(string) => void"); 209AssertType(`quetzalcoatl - no legs, wings`, "string"); 210 } 211 else { 212 log(`snake - no legs, no wings`) 213AssertType(log(`snake - no legs, no wings`), "void"); 214AssertType(log, "(string) => void"); 215AssertType(`snake - no legs, no wings`, "string"); 216 } 217 } 218} 219 220function beastFoo(beast: Object) { 221 if (hasWings(beast) && hasLegs(beast)) { 222AssertType(hasWings(beast) && hasLegs(beast), "boolean"); 223AssertType(hasWings(beast), "boolean"); 224AssertType(hasWings, "(Beast) => x is Winged"); 225AssertType(beast, "Object"); 226AssertType(hasLegs(beast), "boolean"); 227AssertType(hasLegs, "(Beast) => x is Legged"); 228AssertType(beast, "Winged"); 229 230 beast; // Winged & Legged 231AssertType(beast, "Winged & Legged"); 232 } 233 else { 234 beast; 235AssertType(beast, "Object"); 236 } 237 238 if (hasLegs(beast) && hasWings(beast)) { 239AssertType(hasLegs(beast) && hasWings(beast), "boolean"); 240AssertType(hasLegs(beast), "boolean"); 241AssertType(hasLegs, "(Beast) => x is Legged"); 242AssertType(beast, "Object"); 243AssertType(hasWings(beast), "boolean"); 244AssertType(hasWings, "(Beast) => x is Winged"); 245AssertType(beast, "Legged"); 246 247 beast; // Legged & Winged 248AssertType(beast, "Legged & Winged"); 249 } 250} 251 252