diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 94b5874708..ed65908d92 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16057,6 +16057,15 @@ namespace ts { assumeTrue = !assumeTrue; } const valueType = getTypeOfExpression(value); + if ((type.flags & TypeFlags.Unknown) && (operator === SyntaxKind.EqualsEqualsEqualsToken) && assumeTrue) { + if (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) { + return valueType; + } + if (valueType.flags & TypeFlags.Object) { + return nonPrimitiveType; + } + return type; + } if (valueType.flags & TypeFlags.Nullable) { if (!strictNullChecks) { return type; diff --git a/tests/baselines/reference/unknownType2.js b/tests/baselines/reference/unknownType2.js new file mode 100644 index 0000000000..66b763efb5 --- /dev/null +++ b/tests/baselines/reference/unknownType2.js @@ -0,0 +1,189 @@ +//// [unknownType2.ts] +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; + +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 +} + + +//// [unknownType2.js] +"use strict"; +var validate = function (x) { return (x === 'yes' || x === 'no') ? x : 'idk'; }; // No error +var u = undefined; +if (u === 5) { + var y = u.toString(10); +} +if (u === true || u === false) { + var someBool = u; +} +if (u === undefined) { + var undef = u; +} +if (u === null) { + var someNull = u; +} +if (u === symb) { + var symbolAlias = u; +} +if (!(u === 42)) { +} +if (u !== 42) { +} +if (u == 42) { +} +if (u == true) { +} +if (u == Object) { +} +if (u === aString) { + var uString = u; +} +if (u === aBoolean) { + var uString = u; +} +if (u === aNumber) { + var uNumber = u; +} +if (u === anObject) { + var uObject = u; +} +if (u === anObjectLiteral) { + var uObjectLiteral = u; +} +if (u === aUnion) { +} +if (u === anIntersection) { +} +if (u === aFunction) { + var uFunction = u; +} +var NumberEnum; +(function (NumberEnum) { + NumberEnum[NumberEnum["A"] = 0] = "A"; + NumberEnum[NumberEnum["B"] = 1] = "B"; + NumberEnum[NumberEnum["C"] = 2] = "C"; +})(NumberEnum || (NumberEnum = {})); +var StringEnum; +(function (StringEnum) { + StringEnum["A"] = "A"; + StringEnum["B"] = "B"; + StringEnum["C"] = "C"; +})(StringEnum || (StringEnum = {})); +if (u === NumberEnum || u === StringEnum) { + var enumObj = u; +} +if (u === NumberEnum.A) { + var a = u; +} +if (u === StringEnum.B) { + var b = u; +} diff --git a/tests/baselines/reference/unknownType2.symbols b/tests/baselines/reference/unknownType2.symbols new file mode 100644 index 0000000000..577b1186de --- /dev/null +++ b/tests/baselines/reference/unknownType2.symbols @@ -0,0 +1,295 @@ +=== tests/cases/conformance/types/unknown/unknownType2.ts === +type isUnknown = unknown extends T ? true : false; +>isUnknown : Symbol(isUnknown, Decl(unknownType2.ts, 0, 0)) +>T : Symbol(T, Decl(unknownType2.ts, 0, 15)) +>T : Symbol(T, Decl(unknownType2.ts, 0, 15)) + +type isTrue = T; +>isTrue : Symbol(isTrue, Decl(unknownType2.ts, 0, 53)) +>T : Symbol(T, Decl(unknownType2.ts, 1, 12)) +>T : Symbol(T, Decl(unknownType2.ts, 1, 12)) + +type SomeResponse = 'yes' | 'no' | 'idk'; +>SomeResponse : Symbol(SomeResponse, Decl(unknownType2.ts, 1, 32)) + +let validate: (x: unknown) => SomeResponse = x => (x === 'yes' || x === 'no') ? x : 'idk'; // No error +>validate : Symbol(validate, Decl(unknownType2.ts, 4, 3)) +>x : Symbol(x, Decl(unknownType2.ts, 4, 15)) +>SomeResponse : Symbol(SomeResponse, Decl(unknownType2.ts, 1, 32)) +>x : Symbol(x, Decl(unknownType2.ts, 4, 44)) +>x : Symbol(x, Decl(unknownType2.ts, 4, 44)) +>x : Symbol(x, Decl(unknownType2.ts, 4, 44)) +>x : Symbol(x, Decl(unknownType2.ts, 4, 44)) + +const u: unknown = undefined; +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +>undefined : Symbol(undefined) + +declare const symb: unique symbol; +>symb : Symbol(symb, Decl(unknownType2.ts, 8, 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)) +>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, --, --)) +} + +if (u === true || u === false) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) + + const someBool: boolean = u; +>someBool : Symbol(someBool, Decl(unknownType2.ts, 15, 9)) +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +} + +if (u === undefined) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +>undefined : Symbol(undefined) + + const undef: undefined = u; +>undef : Symbol(undef, Decl(unknownType2.ts, 19, 9)) +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +} + +if (u === null) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) + + const someNull: null = u; +>someNull : Symbol(someNull, Decl(unknownType2.ts, 23, 9)) +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +} + +if (u === symb) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +>symb : Symbol(symb, Decl(unknownType2.ts, 8, 13)) + + const symbolAlias: typeof symb = u; +>symbolAlias : Symbol(symbolAlias, Decl(unknownType2.ts, 27, 9)) +>symb : Symbol(symb, Decl(unknownType2.ts, 8, 13)) +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +} + +if (!(u === 42)) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) + + type A = isTrue> +>A : Symbol(A, Decl(unknownType2.ts, 30, 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)) +} + +if (u !== 42) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) + + type B = isTrue> +>B : Symbol(B, Decl(unknownType2.ts, 34, 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)) +} + +if (u == 42) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) + + type C = isTrue> +>C : Symbol(C, Decl(unknownType2.ts, 38, 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)) +} + +if (u == true) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) + + type D = isTrue> +>D : Symbol(D, Decl(unknownType2.ts, 42, 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)) +} + +if (u == Object) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + type E = isTrue> +>E : Symbol(E, Decl(unknownType2.ts, 46, 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)) + +declare const aBoolean: boolean; +>aBoolean : Symbol(aBoolean, Decl(unknownType2.ts, 51, 13)) + +declare const aNumber: number; +>aNumber : Symbol(aNumber, Decl(unknownType2.ts, 52, 13)) + +declare const anObject: object; +>anObject : Symbol(anObject, Decl(unknownType2.ts, 53, 13)) + +declare const anObjectLiteral: { x: number }; +>anObjectLiteral : Symbol(anObjectLiteral, Decl(unknownType2.ts, 54, 13)) +>x : Symbol(x, Decl(unknownType2.ts, 54, 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)) + +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)) + +declare const aFunction: () => number; +>aFunction : Symbol(aFunction, Decl(unknownType2.ts, 57, 13)) + +if (u === aString) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +>aString : Symbol(aString, Decl(unknownType2.ts, 50, 13)) + + let uString: string = u; +>uString : Symbol(uString, Decl(unknownType2.ts, 60, 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)) + + let uString: boolean = u; +>uString : Symbol(uString, Decl(unknownType2.ts, 64, 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)) + + let uNumber: number = u; +>uNumber : Symbol(uNumber, Decl(unknownType2.ts, 68, 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)) + + let uObject: object = u; +>uObject : Symbol(uObject, Decl(unknownType2.ts, 72, 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)) + + let uObjectLiteral: object = u; +>uObjectLiteral : Symbol(uObjectLiteral, Decl(unknownType2.ts, 76, 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)) + + type unionDoesNotNarrow = isTrue> +>unionDoesNotNarrow : Symbol(unionDoesNotNarrow, Decl(unknownType2.ts, 79, 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)) +} + +if (u === anIntersection) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +>anIntersection : Symbol(anIntersection, Decl(unknownType2.ts, 56, 13)) + + type intersectionDoesNotNarrow = isTrue> +>intersectionDoesNotNarrow : Symbol(intersectionDoesNotNarrow, Decl(unknownType2.ts, 83, 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)) +} + +if (u === aFunction) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +>aFunction : Symbol(aFunction, Decl(unknownType2.ts, 57, 13)) + + let uFunction: object = u; +>uFunction : Symbol(uFunction, Decl(unknownType2.ts, 88, 7)) +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +} + +enum NumberEnum { +>NumberEnum : Symbol(NumberEnum, Decl(unknownType2.ts, 89, 1)) + + A, +>A : Symbol(NumberEnum.A, Decl(unknownType2.ts, 91, 17)) + + B, +>B : Symbol(NumberEnum.B, Decl(unknownType2.ts, 92, 6)) + + C +>C : Symbol(NumberEnum.C, Decl(unknownType2.ts, 93, 6)) +} + +enum StringEnum { +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 95, 1)) + + A = "A", +>A : Symbol(StringEnum.A, Decl(unknownType2.ts, 97, 17)) + + B = "B", +>B : Symbol(StringEnum.B, Decl(unknownType2.ts, 98, 12)) + + C = "C" +>C : Symbol(StringEnum.C, Decl(unknownType2.ts, 99, 12)) +} + +if (u === NumberEnum || u === StringEnum) { +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +>NumberEnum : Symbol(NumberEnum, Decl(unknownType2.ts, 89, 1)) +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +>StringEnum : Symbol(StringEnum, Decl(unknownType2.ts, 95, 1)) + + let enumObj: object = u; +>enumObj : Symbol(enumObj, Decl(unknownType2.ts, 104, 7)) +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +} + +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)) + + 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)) +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +} + +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)) + + 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)) +>u : Symbol(u, Decl(unknownType2.ts, 6, 5)) +} + diff --git a/tests/baselines/reference/unknownType2.types b/tests/baselines/reference/unknownType2.types new file mode 100644 index 0000000000..f90d85525c --- /dev/null +++ b/tests/baselines/reference/unknownType2.types @@ -0,0 +1,327 @@ +=== tests/cases/conformance/types/unknown/unknownType2.ts === +type isUnknown = unknown extends T ? true : false; +>isUnknown : isUnknown +>true : true +>false : false + +type isTrue = T; +>isTrue : T +>true : true + +type SomeResponse = 'yes' | 'no' | 'idk'; +>SomeResponse : SomeResponse + +let validate: (x: unknown) => SomeResponse = x => (x === 'yes' || x === 'no') ? x : 'idk'; // No error +>validate : (x: unknown) => SomeResponse +>x : unknown +>x => (x === 'yes' || x === 'no') ? x : 'idk' : (x: unknown) => "yes" | "no" | "idk" +>x : unknown +>(x === 'yes' || x === 'no') ? x : 'idk' : SomeResponse +>(x === 'yes' || x === 'no') : boolean +>x === 'yes' || x === 'no' : boolean +>x === 'yes' : boolean +>x : unknown +>'yes' : "yes" +>x === 'no' : boolean +>x : unknown +>'no' : "no" +>x : "yes" | "no" +>'idk' : "idk" + +const u: unknown = undefined; +>u : unknown +>undefined : undefined + +declare const symb: unique symbol; +>symb : unique symbol + +if (u === 5) { +>u === 5 : boolean +>u : unknown +>5 : 5 + + const y = u.toString(10); +>y : string +>u.toString(10) : string +>u.toString : (radix?: number | undefined) => string +>u : 5 +>toString : (radix?: number | undefined) => string +>10 : 10 +} + +if (u === true || u === false) { +>u === true || u === false : boolean +>u === true : boolean +>u : unknown +>true : true +>u === false : boolean +>u : unknown +>false : false + + const someBool: boolean = u; +>someBool : boolean +>u : boolean +} + +if (u === undefined) { +>u === undefined : boolean +>u : unknown +>undefined : undefined + + const undef: undefined = u; +>undef : undefined +>u : undefined +} + +if (u === null) { +>u === null : boolean +>u : unknown +>null : null + + const someNull: null = u; +>someNull : null +>null : null +>u : null +} + +if (u === symb) { +>u === symb : boolean +>u : unknown +>symb : unique symbol + + const symbolAlias: typeof symb = u; +>symbolAlias : unique symbol +>symb : unique symbol +>u : unique symbol +} + +if (!(u === 42)) { +>!(u === 42) : boolean +>(u === 42) : boolean +>u === 42 : boolean +>u : unknown +>42 : 42 + + type A = isTrue> +>A : true +>u : unknown +} + +if (u !== 42) { +>u !== 42 : boolean +>u : unknown +>42 : 42 + + type B = isTrue> +>B : true +>u : unknown +} + +if (u == 42) { +>u == 42 : boolean +>u : unknown +>42 : 42 + + type C = isTrue> +>C : true +>u : unknown +} + +if (u == true) { +>u == true : boolean +>u : unknown +>true : true + + type D = isTrue> +>D : true +>u : unknown +} + +if (u == Object) { +>u == Object : boolean +>u : unknown +>Object : ObjectConstructor + + type E = isTrue> +>E : true +>u : unknown +} + +declare const aString: string; +>aString : string + +declare const aBoolean: boolean; +>aBoolean : boolean + +declare const aNumber: number; +>aNumber : number + +declare const anObject: object; +>anObject : object + +declare const anObjectLiteral: { x: number }; +>anObjectLiteral : { x: number; } +>x : number + +declare const aUnion: { x: number } | { y: string }; +>aUnion : { x: number; } | { y: string; } +>x : number +>y : string + +declare const anIntersection: { x: number } & { y: string }; +>anIntersection : { x: number; } & { y: string; } +>x : number +>y : string + +declare const aFunction: () => number; +>aFunction : () => number + +if (u === aString) { +>u === aString : boolean +>u : unknown +>aString : string + + let uString: string = u; +>uString : string +>u : string +} + +if (u === aBoolean) { +>u === aBoolean : boolean +>u : unknown +>aBoolean : boolean + + let uString: boolean = u; +>uString : boolean +>u : boolean +} + +if (u === aNumber) { +>u === aNumber : boolean +>u : unknown +>aNumber : number + + let uNumber: number = u; +>uNumber : number +>u : number +} + +if (u === anObject) { +>u === anObject : boolean +>u : unknown +>anObject : object + + let uObject: object = u; +>uObject : object +>u : object +} + +if (u === anObjectLiteral) { +>u === anObjectLiteral : boolean +>u : unknown +>anObjectLiteral : { x: number; } + + let uObjectLiteral: object = u; +>uObjectLiteral : object +>u : object +} + +if (u === aUnion) { +>u === aUnion : boolean +>u : unknown +>aUnion : { x: number; } | { y: string; } + + type unionDoesNotNarrow = isTrue> +>unionDoesNotNarrow : true +>u : unknown +} + +if (u === anIntersection) { +>u === anIntersection : boolean +>u : unknown +>anIntersection : { x: number; } & { y: string; } + + type intersectionDoesNotNarrow = isTrue> +>intersectionDoesNotNarrow : true +>u : unknown +} + +if (u === aFunction) { +>u === aFunction : boolean +>u : unknown +>aFunction : () => number + + let uFunction: object = u; +>uFunction : object +>u : object +} + +enum NumberEnum { +>NumberEnum : NumberEnum + + A, +>A : NumberEnum.A + + B, +>B : NumberEnum.B + + C +>C : NumberEnum.C +} + +enum StringEnum { +>StringEnum : StringEnum + + A = "A", +>A : StringEnum.A +>"A" : "A" + + B = "B", +>B : StringEnum.B +>"B" : "B" + + C = "C" +>C : StringEnum.C +>"C" : "C" +} + +if (u === NumberEnum || u === StringEnum) { +>u === NumberEnum || u === StringEnum : boolean +>u === NumberEnum : boolean +>u : unknown +>NumberEnum : typeof NumberEnum +>u === StringEnum : boolean +>u : unknown +>StringEnum : typeof StringEnum + + let enumObj: object = u; +>enumObj : object +>u : object +} + +if(u === NumberEnum.A) { +>u === NumberEnum.A : boolean +>u : unknown +>NumberEnum.A : NumberEnum.A +>NumberEnum : typeof NumberEnum +>A : NumberEnum.A + + let a: NumberEnum.A = u +>a : NumberEnum.A +>NumberEnum : any +>u : NumberEnum.A +} + +if(u === StringEnum.B) { +>u === StringEnum.B : boolean +>u : unknown +>StringEnum.B : StringEnum.B +>StringEnum : typeof StringEnum +>B : StringEnum.B + + let b: StringEnum.B = u +>b : StringEnum.B +>StringEnum : any +>u : StringEnum.B +} + diff --git a/tests/cases/conformance/types/unknown/unknownType2.ts b/tests/cases/conformance/types/unknown/unknownType2.ts new file mode 100644 index 0000000000..f8700958d6 --- /dev/null +++ b/tests/cases/conformance/types/unknown/unknownType2.ts @@ -0,0 +1,116 @@ +// @strict: true + +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; + +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 +}