Merge pull request #26941 from jack-williams/narrow-unknown-with-triple-equals

Fix #25172: Add narrowing for `unknown` with triple equals
This commit is contained in:
Ryan Cavanaugh 2019-01-29 16:43:50 -08:00 committed by GitHub
commit 0df89cc96f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 936 additions and 0 deletions

View file

@ -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;

View file

@ -0,0 +1,189 @@
//// [unknownType2.ts]
type isUnknown<T> = unknown extends T ? true : false;
type isTrue<T extends true> = 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<isUnknown<typeof u>>
}
if (u !== 42) {
type B = isTrue<isUnknown<typeof u>>
}
if (u == 42) {
type C = isTrue<isUnknown<typeof u>>
}
if (u == true) {
type D = isTrue<isUnknown<typeof u>>
}
if (u == Object) {
type E = isTrue<isUnknown<typeof u>>
}
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<isUnknown<typeof u>>
}
if (u === anIntersection) {
type intersectionDoesNotNarrow = isTrue<isUnknown<typeof u>>
}
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;
}

View file

@ -0,0 +1,295 @@
=== tests/cases/conformance/types/unknown/unknownType2.ts ===
type isUnknown<T> = 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 extends true> = 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<isUnknown<typeof u>>
>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<isUnknown<typeof u>>
>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<isUnknown<typeof u>>
>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<isUnknown<typeof u>>
>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<isUnknown<typeof u>>
>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<isUnknown<typeof u>>
>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<isUnknown<typeof u>>
>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))
}

View file

@ -0,0 +1,327 @@
=== tests/cases/conformance/types/unknown/unknownType2.ts ===
type isUnknown<T> = unknown extends T ? true : false;
>isUnknown : isUnknown<T>
>true : true
>false : false
type isTrue<T extends true> = 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<isUnknown<typeof u>>
>A : true
>u : unknown
}
if (u !== 42) {
>u !== 42 : boolean
>u : unknown
>42 : 42
type B = isTrue<isUnknown<typeof u>>
>B : true
>u : unknown
}
if (u == 42) {
>u == 42 : boolean
>u : unknown
>42 : 42
type C = isTrue<isUnknown<typeof u>>
>C : true
>u : unknown
}
if (u == true) {
>u == true : boolean
>u : unknown
>true : true
type D = isTrue<isUnknown<typeof u>>
>D : true
>u : unknown
}
if (u == Object) {
>u == Object : boolean
>u : unknown
>Object : ObjectConstructor
type E = isTrue<isUnknown<typeof u>>
>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<isUnknown<typeof u>>
>unionDoesNotNarrow : true
>u : unknown
}
if (u === anIntersection) {
>u === anIntersection : boolean
>u : unknown
>anIntersection : { x: number; } & { y: string; }
type intersectionDoesNotNarrow = isTrue<isUnknown<typeof u>>
>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
}

View file

@ -0,0 +1,116 @@
// @strict: true
type isUnknown<T> = unknown extends T ? true : false;
type isTrue<T extends true> = 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<isUnknown<typeof u>>
}
if (u !== 42) {
type B = isTrue<isUnknown<typeof u>>
}
if (u == 42) {
type C = isTrue<isUnknown<typeof u>>
}
if (u == true) {
type D = isTrue<isUnknown<typeof u>>
}
if (u == Object) {
type E = isTrue<isUnknown<typeof u>>
}
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<isUnknown<typeof u>>
}
if (u === anIntersection) {
type intersectionDoesNotNarrow = isTrue<isUnknown<typeof u>>
}
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
}