diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2e6259b668..a4c4761fb5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16152,13 +16152,37 @@ namespace ts { } function narrowTypeBySwitchOnDiscriminant(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number) { - // We only narrow if all case expressions specify values with unit types + // We only narrow if all case expressions specify + // values with unit types, except for the case where + // `type` is unknown. In this instance we map object + // types to the nonPrimitive type and narrow with that. const switchTypes = getSwitchClauseTypes(switchStatement); if (!switchTypes.length) { return type; } const clauseTypes = switchTypes.slice(clauseStart, clauseEnd); const hasDefaultClause = clauseStart === clauseEnd || contains(clauseTypes, neverType); + if ((type.flags & TypeFlags.Unknown) && !hasDefaultClause) { + let groundClauseTypes: Type[] | undefined = undefined; + for (let i = 0; i < clauseTypes.length; i += 1) { + const t = clauseTypes[i]; + if (t.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) { + if (groundClauseTypes !== undefined) { + groundClauseTypes.push(t) + } + } + else if (t.flags & TypeFlags.Object) { + if (groundClauseTypes === undefined) { + groundClauseTypes = clauseTypes.slice(0, i); + } + groundClauseTypes.push(nonPrimitiveType); + } + else { + return type; + } + } + return getUnionType(groundClauseTypes === undefined ? clauseTypes : groundClauseTypes); + } const discriminantType = getUnionType(clauseTypes); const caseType = discriminantType.flags & TypeFlags.Never ? neverType : diff --git a/tests/baselines/reference/unknownType2.errors.txt b/tests/baselines/reference/unknownType2.errors.txt new file mode 100644 index 0000000000..5f08804b9e --- /dev/null +++ b/tests/baselines/reference/unknownType2.errors.txt @@ -0,0 +1,231 @@ +tests/cases/conformance/types/unknown/unknownType2.ts(216,13): error TS2322: Type '"yes" | "no" | "maybe"' is not assignable to type 'SomeResponse'. + Type '"maybe"' is not assignable to type 'SomeResponse'. + + +==== tests/cases/conformance/types/unknown/unknownType2.ts (1 errors) ==== + type isUnknown = unknown extends T ? true : false; + type isTrue = T; + + type SomeResponse = 'yes' | 'no' | 'idk'; + let validate: (x: unknown) => SomeResponse = x => (x === 'yes' || x === 'no') ? x : 'idk'; // No error + + const u: unknown = undefined; + + declare const symb: unique symbol; + declare const symbNonUnique: symbol; + + if (u === 5) { + const y = u.toString(10); + } + + if (u === true || u === false) { + const someBool: boolean = u; + } + + if (u === undefined) { + const undef: undefined = u; + } + + if (u === null) { + const someNull: null = u; + } + + if (u === symb) { + const symbolAlias: typeof symb = u; + } + + if (!(u === 42)) { + type A = isTrue> + } + + if (u !== 42) { + type B = isTrue> + } + + if (u == 42) { + type C = isTrue> + } + + if (u == true) { + type D = isTrue> + } + + if (u == Object) { + type E = isTrue> + } + + declare const aString: string; + declare const aBoolean: boolean; + declare const aNumber: number; + declare const anObject: object; + declare const anObjectLiteral: { x: number }; + declare const aUnion: { x: number } | { y: string }; + declare const anIntersection: { x: number } & { y: string }; + declare const aFunction: () => number; + + if (u === aString) { + let uString: string = u; + } + + if (u === aBoolean) { + let uString: boolean = u; + } + + if (u === aNumber) { + let uNumber: number = u; + } + + if (u === anObject) { + let uObject: object = u; + } + + if (u === anObjectLiteral) { + let uObjectLiteral: object = u; + } + + if (u === aUnion) { + type unionDoesNotNarrow = isTrue> + } + + if (u === anIntersection) { + type intersectionDoesNotNarrow = isTrue> + } + + if (u === aFunction) { + let uFunction: object = u; + } + + enum NumberEnum { + A, + B, + C + } + + enum StringEnum { + A = "A", + B = "B", + C = "C" + } + + if (u === NumberEnum || u === StringEnum) { + let enumObj: object = u; + } + + if (u === NumberEnum.A) { + let a: NumberEnum.A = u + } + + if (u === StringEnum.B) { + let b: StringEnum.B = u + } + + function switchTestEnum(x: unknown) { + switch (x) { + case StringEnum.A: + const a: StringEnum.A = x; + break; + case StringEnum.B: + const b: StringEnum.B = x; + break; + case StringEnum.C: + const c: StringEnum.C = x; + break; + } + type End = isTrue> + } + + function switchTestCollectEnum(x: unknown) { + switch (x) { + case StringEnum.A: + const a: StringEnum.A = x; + case StringEnum.B: + const b: StringEnum.A | StringEnum.B = x; + case StringEnum.C: + const c: StringEnum.A | StringEnum.B | StringEnum.C = x; + const all: StringEnum = x; + return; + } + type End = isTrue> + } + + function switchTestLiterals(x: unknown) { + switch (x) { + case 1: + const one: 1 = x; + break; + case 2: + const two: 2 = x; + break; + case 3: + const three: 3 = x; + break; + case true: + const t: true = x; + break; + case false: + const f: false = x; + break; + case "A": + const a: "A" = x; + break; + case undefined: + const undef: undefined = x; + break; + case null: + const llun: null = x; + break; + case symb: + const anotherSymbol: typeof symb = x; + break; + case symbNonUnique: + const nonUniqueSymbol: symbol = x; + break; + } + type End = isTrue> + } + + function switchTestObjects(x: unknown, y: () => void, z: { prop: number }) { + switch (x) { + case true: + case false: + const bool: boolean = x; + break; + case y: + const obj1: object = x; + break; + case z: + const obj2: object = x; + break; + } + type End = isTrue> + } + + function switchResponse(x: unknown): SomeResponse { + switch (x) { + case 'yes': + case 'no': + case 'idk': + return x; + default: + throw new Error('unknown response'); + } + // Arguably this should be never. + type End = isTrue> + } + + function switchResponseWrong(x: unknown): SomeResponse { + switch (x) { + case 'yes': + case 'no': + case 'maybe': + return x; // error + ~~~~~~~~~ +!!! error TS2322: Type '"yes" | "no" | "maybe"' is not assignable to type 'SomeResponse'. +!!! error TS2322: Type '"maybe"' is not assignable to type 'SomeResponse'. + default: + throw new Error('Can you repeat the question?'); + } + // Arguably this should be never. + type End = isTrue> + } + \ No newline at end of file diff --git a/tests/baselines/reference/unknownType2.js b/tests/baselines/reference/unknownType2.js index 66b763efb5..2ec5b3ed20 100644 --- a/tests/baselines/reference/unknownType2.js +++ b/tests/baselines/reference/unknownType2.js @@ -8,6 +8,7 @@ let validate: (x: unknown) => SomeResponse = x => (x === 'yes' || x === 'no') ? const u: unknown = undefined; declare const symb: unique symbol; +declare const symbNonUnique: symbol; if (u === 5) { const y = u.toString(10); @@ -106,13 +107,120 @@ if (u === NumberEnum || u === StringEnum) { let enumObj: object = u; } -if(u === NumberEnum.A) { +if (u === NumberEnum.A) { let a: NumberEnum.A = u } -if(u === StringEnum.B) { +if (u === StringEnum.B) { let b: StringEnum.B = u } + +function switchTestEnum(x: unknown) { + switch (x) { + case StringEnum.A: + const a: StringEnum.A = x; + break; + case StringEnum.B: + const b: StringEnum.B = x; + break; + case StringEnum.C: + const c: StringEnum.C = x; + break; + } + type End = isTrue> +} + +function switchTestCollectEnum(x: unknown) { + switch (x) { + case StringEnum.A: + const a: StringEnum.A = x; + case StringEnum.B: + const b: StringEnum.A | StringEnum.B = x; + case StringEnum.C: + const c: StringEnum.A | StringEnum.B | StringEnum.C = x; + const all: StringEnum = x; + return; + } + type End = isTrue> +} + +function switchTestLiterals(x: unknown) { + switch (x) { + case 1: + const one: 1 = x; + break; + case 2: + const two: 2 = x; + break; + case 3: + const three: 3 = x; + break; + case true: + const t: true = x; + break; + case false: + const f: false = x; + break; + case "A": + const a: "A" = x; + break; + case undefined: + const undef: undefined = x; + break; + case null: + const llun: null = x; + break; + case symb: + const anotherSymbol: typeof symb = x; + break; + case symbNonUnique: + const nonUniqueSymbol: symbol = x; + break; + } + type End = isTrue> +} + +function switchTestObjects(x: unknown, y: () => void, z: { prop: number }) { + switch (x) { + case true: + case false: + const bool: boolean = x; + break; + case y: + const obj1: object = x; + break; + case z: + const obj2: object = x; + break; + } + type End = isTrue> +} + +function switchResponse(x: unknown): SomeResponse { + switch (x) { + case 'yes': + case 'no': + case 'idk': + return x; + default: + throw new Error('unknown response'); + } + // Arguably this should be never. + type End = isTrue> +} + +function switchResponseWrong(x: unknown): SomeResponse { + switch (x) { + case 'yes': + case 'no': + case 'maybe': + return x; // error + default: + throw new Error('Can you repeat the question?'); + } + // Arguably this should be never. + type End = isTrue> +} //// [unknownType2.js] @@ -187,3 +295,96 @@ if (u === NumberEnum.A) { if (u === StringEnum.B) { var b = u; } +function switchTestEnum(x) { + switch (x) { + case StringEnum.A: + var a = x; + break; + case StringEnum.B: + var b = x; + break; + case StringEnum.C: + var c = x; + break; + } +} +function switchTestCollectEnum(x) { + switch (x) { + case StringEnum.A: + var a = x; + case StringEnum.B: + var b = x; + case StringEnum.C: + var c = x; + var all = x; + return; + } +} +function switchTestLiterals(x) { + switch (x) { + case 1: + var one = x; + break; + case 2: + var two = x; + break; + case 3: + var three = x; + break; + case true: + var t = x; + break; + case false: + var f = x; + break; + case "A": + var a = x; + break; + case undefined: + var undef = x; + break; + case null: + var llun = x; + break; + case symb: + var anotherSymbol = x; + break; + case symbNonUnique: + var nonUniqueSymbol = x; + break; + } +} +function switchTestObjects(x, y, z) { + switch (x) { + case true: + case false: + var bool = x; + break; + case y: + var obj1 = x; + break; + case z: + var obj2 = x; + break; + } +} +function switchResponse(x) { + switch (x) { + case 'yes': + case 'no': + case 'idk': + return x; + default: + throw new Error('unknown response'); + } +} +function switchResponseWrong(x) { + switch (x) { + case 'yes': + case 'no': + case 'maybe': + return x; // error + default: + throw new Error('Can you repeat the question?'); + } +} diff --git a/tests/baselines/reference/unknownType2.symbols b/tests/baselines/reference/unknownType2.symbols index 577b1186de..6e871bd4de 100644 --- a/tests/baselines/reference/unknownType2.symbols +++ b/tests/baselines/reference/unknownType2.symbols @@ -28,11 +28,14 @@ const u: unknown = undefined; declare const symb: unique symbol; >symb : Symbol(symb, Decl(unknownType2.ts, 8, 13)) +declare const symbNonUnique: symbol; +>symbNonUnique : Symbol(symbNonUnique, Decl(unknownType2.ts, 9, 13)) + if (u === 5) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) const y = u.toString(10); ->y : Symbol(y, Decl(unknownType2.ts, 11, 9)) +>y : Symbol(y, Decl(unknownType2.ts, 12, 9)) >u.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) >toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) @@ -43,7 +46,7 @@ if (u === true || u === false) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) const someBool: boolean = u; ->someBool : Symbol(someBool, Decl(unknownType2.ts, 15, 9)) +>someBool : Symbol(someBool, Decl(unknownType2.ts, 16, 9)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } @@ -52,7 +55,7 @@ if (u === undefined) { >undefined : Symbol(undefined) const undef: undefined = u; ->undef : Symbol(undef, Decl(unknownType2.ts, 19, 9)) +>undef : Symbol(undef, Decl(unknownType2.ts, 20, 9)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } @@ -60,7 +63,7 @@ if (u === null) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) const someNull: null = u; ->someNull : Symbol(someNull, Decl(unknownType2.ts, 23, 9)) +>someNull : Symbol(someNull, Decl(unknownType2.ts, 24, 9)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } @@ -69,7 +72,7 @@ if (u === symb) { >symb : Symbol(symb, Decl(unknownType2.ts, 8, 13)) const symbolAlias: typeof symb = u; ->symbolAlias : Symbol(symbolAlias, Decl(unknownType2.ts, 27, 9)) +>symbolAlias : Symbol(symbolAlias, Decl(unknownType2.ts, 28, 9)) >symb : Symbol(symb, Decl(unknownType2.ts, 8, 13)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } @@ -78,7 +81,7 @@ if (!(u === 42)) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) type A = isTrue> ->A : Symbol(A, Decl(unknownType2.ts, 30, 18)) +>A : Symbol(A, Decl(unknownType2.ts, 31, 18)) >isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) >isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) @@ -88,7 +91,7 @@ if (u !== 42) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) type B = isTrue> ->B : Symbol(B, Decl(unknownType2.ts, 34, 15)) +>B : Symbol(B, Decl(unknownType2.ts, 35, 15)) >isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) >isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) @@ -98,7 +101,7 @@ if (u == 42) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) type C = isTrue> ->C : Symbol(C, Decl(unknownType2.ts, 38, 14)) +>C : Symbol(C, Decl(unknownType2.ts, 39, 14)) >isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) >isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) @@ -108,7 +111,7 @@ if (u == true) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) type D = isTrue> ->D : Symbol(D, Decl(unknownType2.ts, 42, 16)) +>D : Symbol(D, Decl(unknownType2.ts, 43, 16)) >isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) >isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) @@ -119,92 +122,92 @@ if (u == Object) { >Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) type E = isTrue> ->E : Symbol(E, Decl(unknownType2.ts, 46, 18)) +>E : Symbol(E, Decl(unknownType2.ts, 47, 18)) >isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) >isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } declare const aString: string; ->aString : Symbol(aString, Decl(unknownType2.ts, 50, 13)) +>aString : Symbol(aString, Decl(unknownType2.ts, 51, 13)) declare const aBoolean: boolean; ->aBoolean : Symbol(aBoolean, Decl(unknownType2.ts, 51, 13)) +>aBoolean : Symbol(aBoolean, Decl(unknownType2.ts, 52, 13)) declare const aNumber: number; ->aNumber : Symbol(aNumber, Decl(unknownType2.ts, 52, 13)) +>aNumber : Symbol(aNumber, Decl(unknownType2.ts, 53, 13)) declare const anObject: object; ->anObject : Symbol(anObject, Decl(unknownType2.ts, 53, 13)) +>anObject : Symbol(anObject, Decl(unknownType2.ts, 54, 13)) declare const anObjectLiteral: { x: number }; ->anObjectLiteral : Symbol(anObjectLiteral, Decl(unknownType2.ts, 54, 13)) ->x : Symbol(x, Decl(unknownType2.ts, 54, 32)) +>anObjectLiteral : Symbol(anObjectLiteral, Decl(unknownType2.ts, 55, 13)) +>x : Symbol(x, Decl(unknownType2.ts, 55, 32)) declare const aUnion: { x: number } | { y: string }; ->aUnion : Symbol(aUnion, Decl(unknownType2.ts, 55, 13)) ->x : Symbol(x, Decl(unknownType2.ts, 55, 23)) ->y : Symbol(y, Decl(unknownType2.ts, 55, 39)) +>aUnion : Symbol(aUnion, Decl(unknownType2.ts, 56, 13)) +>x : Symbol(x, Decl(unknownType2.ts, 56, 23)) +>y : Symbol(y, Decl(unknownType2.ts, 56, 39)) declare const anIntersection: { x: number } & { y: string }; ->anIntersection : Symbol(anIntersection, Decl(unknownType2.ts, 56, 13)) ->x : Symbol(x, Decl(unknownType2.ts, 56, 31)) ->y : Symbol(y, Decl(unknownType2.ts, 56, 47)) +>anIntersection : Symbol(anIntersection, Decl(unknownType2.ts, 57, 13)) +>x : Symbol(x, Decl(unknownType2.ts, 57, 31)) +>y : Symbol(y, Decl(unknownType2.ts, 57, 47)) declare const aFunction: () => number; ->aFunction : Symbol(aFunction, Decl(unknownType2.ts, 57, 13)) +>aFunction : Symbol(aFunction, Decl(unknownType2.ts, 58, 13)) if (u === aString) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) ->aString : Symbol(aString, Decl(unknownType2.ts, 50, 13)) +>aString : Symbol(aString, Decl(unknownType2.ts, 51, 13)) let uString: string = u; ->uString : Symbol(uString, Decl(unknownType2.ts, 60, 7)) +>uString : Symbol(uString, Decl(unknownType2.ts, 61, 7)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } if (u === aBoolean) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) ->aBoolean : Symbol(aBoolean, Decl(unknownType2.ts, 51, 13)) +>aBoolean : Symbol(aBoolean, Decl(unknownType2.ts, 52, 13)) let uString: boolean = u; ->uString : Symbol(uString, Decl(unknownType2.ts, 64, 7)) +>uString : Symbol(uString, Decl(unknownType2.ts, 65, 7)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } if (u === aNumber) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) ->aNumber : Symbol(aNumber, Decl(unknownType2.ts, 52, 13)) +>aNumber : Symbol(aNumber, Decl(unknownType2.ts, 53, 13)) let uNumber: number = u; ->uNumber : Symbol(uNumber, Decl(unknownType2.ts, 68, 7)) +>uNumber : Symbol(uNumber, Decl(unknownType2.ts, 69, 7)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } if (u === anObject) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) ->anObject : Symbol(anObject, Decl(unknownType2.ts, 53, 13)) +>anObject : Symbol(anObject, Decl(unknownType2.ts, 54, 13)) let uObject: object = u; ->uObject : Symbol(uObject, Decl(unknownType2.ts, 72, 7)) +>uObject : Symbol(uObject, Decl(unknownType2.ts, 73, 7)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } if (u === anObjectLiteral) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) ->anObjectLiteral : Symbol(anObjectLiteral, Decl(unknownType2.ts, 54, 13)) +>anObjectLiteral : Symbol(anObjectLiteral, Decl(unknownType2.ts, 55, 13)) let uObjectLiteral: object = u; ->uObjectLiteral : Symbol(uObjectLiteral, Decl(unknownType2.ts, 76, 7)) +>uObjectLiteral : Symbol(uObjectLiteral, Decl(unknownType2.ts, 77, 7)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } if (u === aUnion) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) ->aUnion : Symbol(aUnion, Decl(unknownType2.ts, 55, 13)) +>aUnion : Symbol(aUnion, Decl(unknownType2.ts, 56, 13)) type unionDoesNotNarrow = isTrue> ->unionDoesNotNarrow : Symbol(unionDoesNotNarrow, Decl(unknownType2.ts, 79, 19)) +>unionDoesNotNarrow : Symbol(unionDoesNotNarrow, Decl(unknownType2.ts, 80, 19)) >isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) >isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) @@ -212,10 +215,10 @@ if (u === aUnion) { if (u === anIntersection) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) ->anIntersection : Symbol(anIntersection, Decl(unknownType2.ts, 56, 13)) +>anIntersection : Symbol(anIntersection, Decl(unknownType2.ts, 57, 13)) type intersectionDoesNotNarrow = isTrue> ->intersectionDoesNotNarrow : Symbol(intersectionDoesNotNarrow, Decl(unknownType2.ts, 83, 27)) +>intersectionDoesNotNarrow : Symbol(intersectionDoesNotNarrow, Decl(unknownType2.ts, 84, 27)) >isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) >isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) @@ -223,73 +226,359 @@ if (u === anIntersection) { if (u === aFunction) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) ->aFunction : Symbol(aFunction, Decl(unknownType2.ts, 57, 13)) +>aFunction : Symbol(aFunction, Decl(unknownType2.ts, 58, 13)) let uFunction: object = u; ->uFunction : Symbol(uFunction, Decl(unknownType2.ts, 88, 7)) +>uFunction : Symbol(uFunction, Decl(unknownType2.ts, 89, 7)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } enum NumberEnum { ->NumberEnum : Symbol(NumberEnum, Decl(unknownType2.ts, 89, 1)) +>NumberEnum : Symbol(NumberEnum, Decl(unknownType2.ts, 90, 1)) A, ->A : Symbol(NumberEnum.A, Decl(unknownType2.ts, 91, 17)) +>A : Symbol(NumberEnum.A, Decl(unknownType2.ts, 92, 17)) B, ->B : Symbol(NumberEnum.B, Decl(unknownType2.ts, 92, 6)) +>B : Symbol(NumberEnum.B, Decl(unknownType2.ts, 93, 6)) C ->C : Symbol(NumberEnum.C, Decl(unknownType2.ts, 93, 6)) +>C : Symbol(NumberEnum.C, Decl(unknownType2.ts, 94, 6)) } enum StringEnum { ->StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 95, 1)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) A = "A", ->A : Symbol(StringEnum.A, Decl(unknownType2.ts, 97, 17)) +>A : Symbol(StringEnum.A, Decl(unknownType2.ts, 98, 17)) B = "B", ->B : Symbol(StringEnum.B, Decl(unknownType2.ts, 98, 12)) +>B : Symbol(StringEnum.B, Decl(unknownType2.ts, 99, 12)) C = "C" ->C : Symbol(StringEnum.C, Decl(unknownType2.ts, 99, 12)) +>C : Symbol(StringEnum.C, Decl(unknownType2.ts, 100, 12)) } if (u === NumberEnum || u === StringEnum) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) ->NumberEnum : Symbol(NumberEnum, Decl(unknownType2.ts, 89, 1)) +>NumberEnum : Symbol(NumberEnum, Decl(unknownType2.ts, 90, 1)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) ->StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 95, 1)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) let enumObj: object = u; ->enumObj : Symbol(enumObj, Decl(unknownType2.ts, 104, 7)) +>enumObj : Symbol(enumObj, Decl(unknownType2.ts, 105, 7)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } -if(u === NumberEnum.A) { +if (u === NumberEnum.A) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) ->NumberEnum.A : Symbol(NumberEnum.A, Decl(unknownType2.ts, 91, 17)) ->NumberEnum : Symbol(NumberEnum, Decl(unknownType2.ts, 89, 1)) ->A : Symbol(NumberEnum.A, Decl(unknownType2.ts, 91, 17)) +>NumberEnum.A : Symbol(NumberEnum.A, Decl(unknownType2.ts, 92, 17)) +>NumberEnum : Symbol(NumberEnum, Decl(unknownType2.ts, 90, 1)) +>A : Symbol(NumberEnum.A, Decl(unknownType2.ts, 92, 17)) let a: NumberEnum.A = u ->a : Symbol(a, Decl(unknownType2.ts, 108, 7)) ->NumberEnum : Symbol(NumberEnum, Decl(unknownType2.ts, 89, 1)) ->A : Symbol(NumberEnum.A, Decl(unknownType2.ts, 91, 17)) +>a : Symbol(a, Decl(unknownType2.ts, 109, 7)) +>NumberEnum : Symbol(NumberEnum, Decl(unknownType2.ts, 90, 1)) +>A : Symbol(NumberEnum.A, Decl(unknownType2.ts, 92, 17)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } -if(u === StringEnum.B) { +if (u === StringEnum.B) { >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) ->StringEnum.B : Symbol(StringEnum.B, Decl(unknownType2.ts, 98, 12)) ->StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 95, 1)) ->B : Symbol(StringEnum.B, Decl(unknownType2.ts, 98, 12)) +>StringEnum.B : Symbol(StringEnum.B, Decl(unknownType2.ts, 99, 12)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>B : Symbol(StringEnum.B, Decl(unknownType2.ts, 99, 12)) let b: StringEnum.B = u ->b : Symbol(b, Decl(unknownType2.ts, 112, 7)) ->StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 95, 1)) ->B : Symbol(StringEnum.B, Decl(unknownType2.ts, 98, 12)) +>b : Symbol(b, Decl(unknownType2.ts, 113, 7)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>B : Symbol(StringEnum.B, Decl(unknownType2.ts, 99, 12)) >u : Symbol(u, Decl(unknownType2.ts, 6, 5)) } +function switchTestEnum(x: unknown) { +>switchTestEnum : Symbol(switchTestEnum, Decl(unknownType2.ts, 114, 1)) +>x : Symbol(x, Decl(unknownType2.ts, 116, 24)) + + switch (x) { +>x : Symbol(x, Decl(unknownType2.ts, 116, 24)) + + case StringEnum.A: +>StringEnum.A : Symbol(StringEnum.A, Decl(unknownType2.ts, 98, 17)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>A : Symbol(StringEnum.A, Decl(unknownType2.ts, 98, 17)) + + const a: StringEnum.A = x; +>a : Symbol(a, Decl(unknownType2.ts, 119, 17)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>A : Symbol(StringEnum.A, Decl(unknownType2.ts, 98, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 116, 24)) + + break; + case StringEnum.B: +>StringEnum.B : Symbol(StringEnum.B, Decl(unknownType2.ts, 99, 12)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>B : Symbol(StringEnum.B, Decl(unknownType2.ts, 99, 12)) + + const b: StringEnum.B = x; +>b : Symbol(b, Decl(unknownType2.ts, 122, 17)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>B : Symbol(StringEnum.B, Decl(unknownType2.ts, 99, 12)) +>x : Symbol(x, Decl(unknownType2.ts, 116, 24)) + + break; + case StringEnum.C: +>StringEnum.C : Symbol(StringEnum.C, Decl(unknownType2.ts, 100, 12)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>C : Symbol(StringEnum.C, Decl(unknownType2.ts, 100, 12)) + + const c: StringEnum.C = x; +>c : Symbol(c, Decl(unknownType2.ts, 125, 17)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>C : Symbol(StringEnum.C, Decl(unknownType2.ts, 100, 12)) +>x : Symbol(x, Decl(unknownType2.ts, 116, 24)) + + break; + } + type End = isTrue> +>End : Symbol(End, Decl(unknownType2.ts, 127, 5)) +>isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) +>isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) +>x : Symbol(x, Decl(unknownType2.ts, 116, 24)) +} + +function switchTestCollectEnum(x: unknown) { +>switchTestCollectEnum : Symbol(switchTestCollectEnum, Decl(unknownType2.ts, 129, 1)) +>x : Symbol(x, Decl(unknownType2.ts, 131, 31)) + + switch (x) { +>x : Symbol(x, Decl(unknownType2.ts, 131, 31)) + + case StringEnum.A: +>StringEnum.A : Symbol(StringEnum.A, Decl(unknownType2.ts, 98, 17)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>A : Symbol(StringEnum.A, Decl(unknownType2.ts, 98, 17)) + + const a: StringEnum.A = x; +>a : Symbol(a, Decl(unknownType2.ts, 134, 17)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>A : Symbol(StringEnum.A, Decl(unknownType2.ts, 98, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 131, 31)) + + case StringEnum.B: +>StringEnum.B : Symbol(StringEnum.B, Decl(unknownType2.ts, 99, 12)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>B : Symbol(StringEnum.B, Decl(unknownType2.ts, 99, 12)) + + const b: StringEnum.A | StringEnum.B = x; +>b : Symbol(b, Decl(unknownType2.ts, 136, 17)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>A : Symbol(StringEnum.A, Decl(unknownType2.ts, 98, 17)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>B : Symbol(StringEnum.B, Decl(unknownType2.ts, 99, 12)) +>x : Symbol(x, Decl(unknownType2.ts, 131, 31)) + + case StringEnum.C: +>StringEnum.C : Symbol(StringEnum.C, Decl(unknownType2.ts, 100, 12)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>C : Symbol(StringEnum.C, Decl(unknownType2.ts, 100, 12)) + + const c: StringEnum.A | StringEnum.B | StringEnum.C = x; +>c : Symbol(c, Decl(unknownType2.ts, 138, 17)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>A : Symbol(StringEnum.A, Decl(unknownType2.ts, 98, 17)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>B : Symbol(StringEnum.B, Decl(unknownType2.ts, 99, 12)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>C : Symbol(StringEnum.C, Decl(unknownType2.ts, 100, 12)) +>x : Symbol(x, Decl(unknownType2.ts, 131, 31)) + + const all: StringEnum = x; +>all : Symbol(all, Decl(unknownType2.ts, 139, 17)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 96, 1)) +>x : Symbol(x, Decl(unknownType2.ts, 131, 31)) + + return; + } + type End = isTrue> +>End : Symbol(End, Decl(unknownType2.ts, 141, 5)) +>isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) +>isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) +>x : Symbol(x, Decl(unknownType2.ts, 131, 31)) +} + +function switchTestLiterals(x: unknown) { +>switchTestLiterals : Symbol(switchTestLiterals, Decl(unknownType2.ts, 143, 1)) +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) + + switch (x) { +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) + + case 1: + const one: 1 = x; +>one : Symbol(one, Decl(unknownType2.ts, 148, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) + + break; + case 2: + const two: 2 = x; +>two : Symbol(two, Decl(unknownType2.ts, 151, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) + + break; + case 3: + const three: 3 = x; +>three : Symbol(three, Decl(unknownType2.ts, 154, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) + + break; + case true: + const t: true = x; +>t : Symbol(t, Decl(unknownType2.ts, 157, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) + + break; + case false: + const f: false = x; +>f : Symbol(f, Decl(unknownType2.ts, 160, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) + + break; + case "A": + const a: "A" = x; +>a : Symbol(a, Decl(unknownType2.ts, 163, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) + + break; + case undefined: +>undefined : Symbol(undefined) + + const undef: undefined = x; +>undef : Symbol(undef, Decl(unknownType2.ts, 166, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) + + break; + case null: + const llun: null = x; +>llun : Symbol(llun, Decl(unknownType2.ts, 169, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) + + break; + case symb: +>symb : Symbol(symb, Decl(unknownType2.ts, 8, 13)) + + const anotherSymbol: typeof symb = x; +>anotherSymbol : Symbol(anotherSymbol, Decl(unknownType2.ts, 172, 17)) +>symb : Symbol(symb, Decl(unknownType2.ts, 8, 13)) +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) + + break; + case symbNonUnique: +>symbNonUnique : Symbol(symbNonUnique, Decl(unknownType2.ts, 9, 13)) + + const nonUniqueSymbol: symbol = x; +>nonUniqueSymbol : Symbol(nonUniqueSymbol, Decl(unknownType2.ts, 175, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) + + break; + } + type End = isTrue> +>End : Symbol(End, Decl(unknownType2.ts, 177, 5)) +>isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) +>isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) +>x : Symbol(x, Decl(unknownType2.ts, 145, 28)) +} + +function switchTestObjects(x: unknown, y: () => void, z: { prop: number }) { +>switchTestObjects : Symbol(switchTestObjects, Decl(unknownType2.ts, 179, 1)) +>x : Symbol(x, Decl(unknownType2.ts, 181, 27)) +>y : Symbol(y, Decl(unknownType2.ts, 181, 38)) +>z : Symbol(z, Decl(unknownType2.ts, 181, 53)) +>prop : Symbol(prop, Decl(unknownType2.ts, 181, 58)) + + switch (x) { +>x : Symbol(x, Decl(unknownType2.ts, 181, 27)) + + case true: + case false: + const bool: boolean = x; +>bool : Symbol(bool, Decl(unknownType2.ts, 185, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 181, 27)) + + break; + case y: +>y : Symbol(y, Decl(unknownType2.ts, 181, 38)) + + const obj1: object = x; +>obj1 : Symbol(obj1, Decl(unknownType2.ts, 188, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 181, 27)) + + break; + case z: +>z : Symbol(z, Decl(unknownType2.ts, 181, 53)) + + const obj2: object = x; +>obj2 : Symbol(obj2, Decl(unknownType2.ts, 191, 17)) +>x : Symbol(x, Decl(unknownType2.ts, 181, 27)) + + break; + } + type End = isTrue> +>End : Symbol(End, Decl(unknownType2.ts, 193, 5)) +>isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) +>isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) +>x : Symbol(x, Decl(unknownType2.ts, 181, 27)) +} + +function switchResponse(x: unknown): SomeResponse { +>switchResponse : Symbol(switchResponse, Decl(unknownType2.ts, 195, 1)) +>x : Symbol(x, Decl(unknownType2.ts, 197, 24)) +>SomeResponse : Symbol(SomeResponse, Decl(unknownType2.ts, 1, 32)) + + switch (x) { +>x : Symbol(x, Decl(unknownType2.ts, 197, 24)) + + case 'yes': + case 'no': + case 'idk': + return x; +>x : Symbol(x, Decl(unknownType2.ts, 197, 24)) + + default: + throw new Error('unknown response'); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } + // Arguably this should be never. + type End = isTrue> +>End : Symbol(End, Decl(unknownType2.ts, 205, 5)) +>isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) +>isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) +>x : Symbol(x, Decl(unknownType2.ts, 197, 24)) +} + +function switchResponseWrong(x: unknown): SomeResponse { +>switchResponseWrong : Symbol(switchResponseWrong, Decl(unknownType2.ts, 208, 1)) +>x : Symbol(x, Decl(unknownType2.ts, 210, 29)) +>SomeResponse : Symbol(SomeResponse, Decl(unknownType2.ts, 1, 32)) + + switch (x) { +>x : Symbol(x, Decl(unknownType2.ts, 210, 29)) + + case 'yes': + case 'no': + case 'maybe': + return x; // error +>x : Symbol(x, Decl(unknownType2.ts, 210, 29)) + + default: + throw new Error('Can you repeat the question?'); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } + // Arguably this should be never. + type End = isTrue> +>End : Symbol(End, Decl(unknownType2.ts, 218, 5)) +>isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) +>isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) +>x : Symbol(x, Decl(unknownType2.ts, 210, 29)) +} + diff --git a/tests/baselines/reference/unknownType2.types b/tests/baselines/reference/unknownType2.types index f90d85525c..7fc3c3d103 100644 --- a/tests/baselines/reference/unknownType2.types +++ b/tests/baselines/reference/unknownType2.types @@ -35,6 +35,9 @@ const u: unknown = undefined; declare const symb: unique symbol; >symb : unique symbol +declare const symbNonUnique: symbol; +>symbNonUnique : symbol + if (u === 5) { >u === 5 : boolean >u : unknown @@ -299,7 +302,7 @@ if (u === NumberEnum || u === StringEnum) { >u : object } -if(u === NumberEnum.A) { +if (u === NumberEnum.A) { >u === NumberEnum.A : boolean >u : unknown >NumberEnum.A : NumberEnum.A @@ -312,7 +315,7 @@ if(u === NumberEnum.A) { >u : NumberEnum.A } -if(u === StringEnum.B) { +if (u === StringEnum.B) { >u === StringEnum.B : boolean >u : unknown >StringEnum.B : StringEnum.B @@ -325,3 +328,302 @@ if(u === StringEnum.B) { >u : StringEnum.B } +function switchTestEnum(x: unknown) { +>switchTestEnum : (x: unknown) => void +>x : unknown + + switch (x) { +>x : unknown + + case StringEnum.A: +>StringEnum.A : StringEnum.A +>StringEnum : typeof StringEnum +>A : StringEnum.A + + const a: StringEnum.A = x; +>a : StringEnum.A +>StringEnum : any +>x : StringEnum.A + + break; + case StringEnum.B: +>StringEnum.B : StringEnum.B +>StringEnum : typeof StringEnum +>B : StringEnum.B + + const b: StringEnum.B = x; +>b : StringEnum.B +>StringEnum : any +>x : StringEnum.B + + break; + case StringEnum.C: +>StringEnum.C : StringEnum.C +>StringEnum : typeof StringEnum +>C : StringEnum.C + + const c: StringEnum.C = x; +>c : StringEnum.C +>StringEnum : any +>x : StringEnum.C + + break; + } + type End = isTrue> +>End : true +>x : unknown +} + +function switchTestCollectEnum(x: unknown) { +>switchTestCollectEnum : (x: unknown) => void +>x : unknown + + switch (x) { +>x : unknown + + case StringEnum.A: +>StringEnum.A : StringEnum.A +>StringEnum : typeof StringEnum +>A : StringEnum.A + + const a: StringEnum.A = x; +>a : StringEnum.A +>StringEnum : any +>x : StringEnum.A + + case StringEnum.B: +>StringEnum.B : StringEnum.B +>StringEnum : typeof StringEnum +>B : StringEnum.B + + const b: StringEnum.A | StringEnum.B = x; +>b : StringEnum.A | StringEnum.B +>StringEnum : any +>StringEnum : any +>x : StringEnum.A | StringEnum.B + + case StringEnum.C: +>StringEnum.C : StringEnum.C +>StringEnum : typeof StringEnum +>C : StringEnum.C + + const c: StringEnum.A | StringEnum.B | StringEnum.C = x; +>c : StringEnum +>StringEnum : any +>StringEnum : any +>StringEnum : any +>x : StringEnum + + const all: StringEnum = x; +>all : StringEnum +>x : StringEnum + + return; + } + type End = isTrue> +>End : true +>x : unknown +} + +function switchTestLiterals(x: unknown) { +>switchTestLiterals : (x: unknown) => void +>x : unknown + + switch (x) { +>x : unknown + + case 1: +>1 : 1 + + const one: 1 = x; +>one : 1 +>x : 1 + + break; + case 2: +>2 : 2 + + const two: 2 = x; +>two : 2 +>x : 2 + + break; + case 3: +>3 : 3 + + const three: 3 = x; +>three : 3 +>x : 3 + + break; + case true: +>true : true + + const t: true = x; +>t : true +>true : true +>x : true + + break; + case false: +>false : false + + const f: false = x; +>f : false +>false : false +>x : false + + break; + case "A": +>"A" : "A" + + const a: "A" = x; +>a : "A" +>x : "A" + + break; + case undefined: +>undefined : undefined + + const undef: undefined = x; +>undef : undefined +>x : undefined + + break; + case null: +>null : null + + const llun: null = x; +>llun : null +>null : null +>x : null + + break; + case symb: +>symb : unique symbol + + const anotherSymbol: typeof symb = x; +>anotherSymbol : unique symbol +>symb : unique symbol +>x : unique symbol + + break; + case symbNonUnique: +>symbNonUnique : symbol + + const nonUniqueSymbol: symbol = x; +>nonUniqueSymbol : symbol +>x : symbol + + break; + } + type End = isTrue> +>End : true +>x : unknown +} + +function switchTestObjects(x: unknown, y: () => void, z: { prop: number }) { +>switchTestObjects : (x: unknown, y: () => void, z: { prop: number; }) => void +>x : unknown +>y : () => void +>z : { prop: number; } +>prop : number + + switch (x) { +>x : unknown + + case true: +>true : true + + case false: +>false : false + + const bool: boolean = x; +>bool : boolean +>x : boolean + + break; + case y: +>y : () => void + + const obj1: object = x; +>obj1 : object +>x : object + + break; + case z: +>z : { prop: number; } + + const obj2: object = x; +>obj2 : object +>x : object + + break; + } + type End = isTrue> +>End : true +>x : unknown +} + +function switchResponse(x: unknown): SomeResponse { +>switchResponse : (x: unknown) => SomeResponse +>x : unknown + + switch (x) { +>x : unknown + + case 'yes': +>'yes' : "yes" + + case 'no': +>'no' : "no" + + case 'idk': +>'idk' : "idk" + + return x; +>x : SomeResponse + + default: + throw new Error('unknown response'); +>new Error('unknown response') : Error +>Error : ErrorConstructor +>'unknown response' : "unknown response" + } + // Arguably this should be never. + type End = isTrue> +>End : true +>x : unknown +} + +function switchResponseWrong(x: unknown): SomeResponse { +>switchResponseWrong : (x: unknown) => SomeResponse +>x : unknown + + switch (x) { +>x : unknown + + case 'yes': +>'yes' : "yes" + + case 'no': +>'no' : "no" + + case 'maybe': +>'maybe' : "maybe" + + return x; // error +>x : "yes" | "no" | "maybe" + + default: + throw new Error('Can you repeat the question?'); +>new Error('Can you repeat the question?') : Error +>Error : ErrorConstructor +>'Can you repeat the question?' : "Can you repeat the question?" + } + // Arguably this should be never. + type End = isTrue> +>End : true +>x : unknown +} + diff --git a/tests/cases/conformance/types/unknown/unknownType2.ts b/tests/cases/conformance/types/unknown/unknownType2.ts index f8700958d6..b3d16654b8 100644 --- a/tests/cases/conformance/types/unknown/unknownType2.ts +++ b/tests/cases/conformance/types/unknown/unknownType2.ts @@ -9,6 +9,7 @@ let validate: (x: unknown) => SomeResponse = x => (x === 'yes' || x === 'no') ? const u: unknown = undefined; declare const symb: unique symbol; +declare const symbNonUnique: symbol; if (u === 5) { const y = u.toString(10); @@ -107,10 +108,117 @@ if (u === NumberEnum || u === StringEnum) { let enumObj: object = u; } -if(u === NumberEnum.A) { +if (u === NumberEnum.A) { let a: NumberEnum.A = u } -if(u === StringEnum.B) { +if (u === StringEnum.B) { let b: StringEnum.B = u } + +function switchTestEnum(x: unknown) { + switch (x) { + case StringEnum.A: + const a: StringEnum.A = x; + break; + case StringEnum.B: + const b: StringEnum.B = x; + break; + case StringEnum.C: + const c: StringEnum.C = x; + break; + } + type End = isTrue> +} + +function switchTestCollectEnum(x: unknown) { + switch (x) { + case StringEnum.A: + const a: StringEnum.A = x; + case StringEnum.B: + const b: StringEnum.A | StringEnum.B = x; + case StringEnum.C: + const c: StringEnum.A | StringEnum.B | StringEnum.C = x; + const all: StringEnum = x; + return; + } + type End = isTrue> +} + +function switchTestLiterals(x: unknown) { + switch (x) { + case 1: + const one: 1 = x; + break; + case 2: + const two: 2 = x; + break; + case 3: + const three: 3 = x; + break; + case true: + const t: true = x; + break; + case false: + const f: false = x; + break; + case "A": + const a: "A" = x; + break; + case undefined: + const undef: undefined = x; + break; + case null: + const llun: null = x; + break; + case symb: + const anotherSymbol: typeof symb = x; + break; + case symbNonUnique: + const nonUniqueSymbol: symbol = x; + break; + } + type End = isTrue> +} + +function switchTestObjects(x: unknown, y: () => void, z: { prop: number }) { + switch (x) { + case true: + case false: + const bool: boolean = x; + break; + case y: + const obj1: object = x; + break; + case z: + const obj2: object = x; + break; + } + type End = isTrue> +} + +function switchResponse(x: unknown): SomeResponse { + switch (x) { + case 'yes': + case 'no': + case 'idk': + return x; + default: + throw new Error('unknown response'); + } + // Arguably this should be never. + type End = isTrue> +} + +function switchResponseWrong(x: unknown): SomeResponse { + switch (x) { + case 'yes': + case 'no': + case 'maybe': + return x; // error + default: + throw new Error('Can you repeat the question?'); + } + // Arguably this should be never. + type End = isTrue> +}