1// @strict: true 2 3type isUnknown<T> = unknown extends T ? true : false; 4type isTrue<T extends true> = T; 5 6type SomeResponse = 'yes' | 'no' | 'idk'; 7let validate: (x: unknown) => SomeResponse = x => (x === 'yes' || x === 'no') ? x : 'idk'; // No error 8 9const u: unknown = undefined; 10 11declare const symb: unique symbol; 12declare const symbNonUnique: symbol; 13 14if (u === 5) { 15 const y = u.toString(10); 16} 17 18if (u === true || u === false) { 19 const someBool: boolean = u; 20} 21 22if (u === undefined) { 23 const undef: undefined = u; 24} 25 26if (u === null) { 27 const someNull: null = u; 28} 29 30if (u === symb) { 31 const symbolAlias: typeof symb = u; 32} 33 34if (!(u === 42)) { 35 type A = isTrue<isUnknown<typeof u>> 36} 37 38if (u !== 42) { 39 type B = isTrue<isUnknown<typeof u>> 40} 41 42if (u == 42) { 43 type C = isTrue<isUnknown<typeof u>> 44} 45 46if (u == true) { 47 type D = isTrue<isUnknown<typeof u>> 48} 49 50if (u == Object) { 51 type E = isTrue<isUnknown<typeof u>> 52} 53 54declare const aString: string; 55declare const aBoolean: boolean; 56declare const aNumber: number; 57declare const anObject: object; 58declare const anObjectLiteral: { x: number }; 59declare const aUnion: { x: number } | { y: string }; 60declare const anIntersection: { x: number } & { y: string }; 61declare const aFunction: () => number; 62 63if (u === aString) { 64 let uString: string = u; 65} 66 67if (u === aBoolean) { 68 let uString: boolean = u; 69} 70 71if (u === aNumber) { 72 let uNumber: number = u; 73} 74 75if (u === anObject) { 76 let uObject: object = u; 77} 78 79if (u === anObjectLiteral) { 80 let uObjectLiteral: object = u; 81} 82 83if (u === aUnion) { 84 type unionDoesNotNarrow = isTrue<isUnknown<typeof u>> 85} 86 87if (u === anIntersection) { 88 type intersectionDoesNotNarrow = isTrue<isUnknown<typeof u>> 89} 90 91if (u === aFunction) { 92 let uFunction: object = u; 93} 94 95enum NumberEnum { 96 A, 97 B, 98 C 99} 100 101enum StringEnum { 102 A = "A", 103 B = "B", 104 C = "C" 105} 106 107if (u === NumberEnum || u === StringEnum) { 108 let enumObj: object = u; 109} 110 111if (u === NumberEnum.A) { 112 let a: NumberEnum.A = u 113} 114 115if (u === StringEnum.B) { 116 let b: StringEnum.B = u 117} 118 119function switchTestEnum(x: unknown) { 120 switch (x) { 121 case StringEnum.A: 122 const a: StringEnum.A = x; 123 break; 124 case StringEnum.B: 125 const b: StringEnum.B = x; 126 break; 127 case StringEnum.C: 128 const c: StringEnum.C = x; 129 break; 130 } 131 type End = isTrue<isUnknown<typeof x>> 132} 133 134function switchTestCollectEnum(x: unknown) { 135 switch (x) { 136 case StringEnum.A: 137 const a: StringEnum.A = x; 138 case StringEnum.B: 139 const b: StringEnum.A | StringEnum.B = x; 140 case StringEnum.C: 141 const c: StringEnum.A | StringEnum.B | StringEnum.C = x; 142 const all: StringEnum = x; 143 return; 144 } 145 type End = isTrue<isUnknown<typeof x>> 146} 147 148function switchTestLiterals(x: unknown) { 149 switch (x) { 150 case 1: 151 const one: 1 = x; 152 break; 153 case 2: 154 const two: 2 = x; 155 break; 156 case 3: 157 const three: 3 = x; 158 break; 159 case true: 160 const t: true = x; 161 break; 162 case false: 163 const f: false = x; 164 break; 165 case "A": 166 const a: "A" = x; 167 break; 168 case undefined: 169 const undef: undefined = x; 170 break; 171 case null: 172 const llun: null = x; 173 break; 174 case symb: 175 const anotherSymbol: typeof symb = x; 176 break; 177 case symbNonUnique: 178 const nonUniqueSymbol: symbol = x; 179 break; 180 } 181 type End = isTrue<isUnknown<typeof x>> 182} 183 184function switchTestObjects(x: unknown, y: () => void, z: { prop: number }) { 185 switch (x) { 186 case true: 187 case false: 188 const bool: boolean = x; 189 break; 190 case y: 191 const obj1: object = x; 192 break; 193 case z: 194 const obj2: object = x; 195 break; 196 } 197 type End = isTrue<isUnknown<typeof x>> 198} 199 200function switchResponse(x: unknown): SomeResponse { 201 switch (x) { 202 case 'yes': 203 case 'no': 204 case 'idk': 205 return x; 206 default: 207 throw new Error('unknown response'); 208 } 209 // Arguably this should be never. 210 type End = isTrue<isUnknown<typeof x>> 211} 212 213function switchResponseWrong(x: unknown): SomeResponse { 214 switch (x) { 215 case 'yes': 216 case 'no': 217 case 'maybe': 218 return x; // error 219 default: 220 throw new Error('Can you repeat the question?'); 221 } 222 // Arguably this should be never. 223 type End = isTrue<isUnknown<typeof x>> 224} 225 226// Repro from #33483 227 228function f2(x: unknown): string | undefined { 229 if (x !== undefined && typeof x !== 'string') { 230 throw new Error(); 231 } 232 return x; 233} 234 235function notNotEquals(u: unknown) { 236 if (u !== NumberEnum) { } 237 else { 238 const o: object = u; 239 } 240 241 if (u !== NumberEnum.A) { } 242 else { 243 const a: NumberEnum.A = u; 244 } 245 246 247 if (u !== NumberEnum.A && u !== NumberEnum.B && u !== StringEnum.A) { } 248 else { 249 const aOrB: NumberEnum.A | NumberEnum.B | StringEnum.A = u; 250 } 251 252 // equivalent to 253 if (!(u === NumberEnum.A || u === NumberEnum.B || u === StringEnum.A)) { } 254 else { 255 const aOrB: NumberEnum.A | NumberEnum.B | StringEnum.A = u; 256 } 257} 258 259 260 261 262