diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9f3c8fa6fd7d6..c36e5075a0e78 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9286,8 +9286,10 @@ namespace ts { return type; } - function getRegularTypeOfLiteralType(type: Type) { - return type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral ? (type).regularType : type; + function getRegularTypeOfLiteralType(type: Type): Type { + return type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral ? (type).regularType : + type.flags & TypeFlags.Union ? getUnionType(sameMap((type).types, getRegularTypeOfLiteralType)) : + type; } function getLiteralType(value: string | number, enumId?: number, symbol?: Symbol) { @@ -12774,10 +12776,12 @@ namespace ts { // all inferences were made to top-level occurrences of the type parameter, and // the type parameter has no constraint or its constraint includes no primitive or literal types, and // the type parameter was fixed during inference or does not occur at top-level in the return type. - const widenLiteralTypes = inference.topLevel && - !hasPrimitiveConstraint(inference.typeParameter) && + const primitiveConstraint = hasPrimitiveConstraint(inference.typeParameter); + const widenLiteralTypes = !primitiveConstraint && inference.topLevel && (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); - const baseCandidates = widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : candidates; + const baseCandidates = primitiveConstraint ? sameMap(candidates, getRegularTypeOfLiteralType) : + widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : + candidates; // If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if // union types were requested or if all inferences were made from the return type position, infer a // union type. Otherwise, infer a common supertype. diff --git a/tests/baselines/reference/bestCommonTypeOfConditionalExpressions2.types b/tests/baselines/reference/bestCommonTypeOfConditionalExpressions2.types index 997f4ea52492d..ad09c274c9ba6 100644 --- a/tests/baselines/reference/bestCommonTypeOfConditionalExpressions2.types +++ b/tests/baselines/reference/bestCommonTypeOfConditionalExpressions2.types @@ -30,7 +30,7 @@ var derived2: Derived2; var r2 = true ? 1 : ''; >r2 : string | number ->true ? 1 : '' : 1 | "" +>true ? 1 : '' : "" | 1 >true : true >1 : 1 >'' : "" diff --git a/tests/baselines/reference/callExpressionWithTypeParameterConstrainedToOuterTypeParameter.types b/tests/baselines/reference/callExpressionWithTypeParameterConstrainedToOuterTypeParameter.types index 69188eacd1a1c..76b8a51370261 100644 --- a/tests/baselines/reference/callExpressionWithTypeParameterConstrainedToOuterTypeParameter.types +++ b/tests/baselines/reference/callExpressionWithTypeParameterConstrainedToOuterTypeParameter.types @@ -15,7 +15,7 @@ var i: I; >I : I var y = i(""); // y should be string ->y : string +>y : "" >i("") : "" >i : I >"" : "" diff --git a/tests/baselines/reference/conditionalExpression1.types b/tests/baselines/reference/conditionalExpression1.types index d5695b64c3860..b5e177b4c7805 100644 --- a/tests/baselines/reference/conditionalExpression1.types +++ b/tests/baselines/reference/conditionalExpression1.types @@ -1,8 +1,8 @@ === tests/cases/compiler/conditionalExpression1.ts === var x: boolean = (true ? 1 : ""); // should be an error >x : boolean ->(true ? 1 : "") : 1 | "" ->true ? 1 : "" : 1 | "" +>(true ? 1 : "") : "" | 1 +>true ? 1 : "" : "" | 1 >true : true >1 : 1 >"" : "" diff --git a/tests/baselines/reference/conditionalExpressions2.types b/tests/baselines/reference/conditionalExpressions2.types index 325a281738faf..3067f212f3c10 100644 --- a/tests/baselines/reference/conditionalExpressions2.types +++ b/tests/baselines/reference/conditionalExpressions2.types @@ -15,7 +15,7 @@ var b = false ? undefined : 0; var c = false ? 1 : 0; >c : number ->false ? 1 : 0 : 1 | 0 +>false ? 1 : 0 : 0 | 1 >false : false >1 : 1 >0 : 0 diff --git a/tests/baselines/reference/conditionalOperatorWithIdenticalBCT.types b/tests/baselines/reference/conditionalOperatorWithIdenticalBCT.types index a9767c72fc7cd..6f7a4db20e2d1 100644 --- a/tests/baselines/reference/conditionalOperatorWithIdenticalBCT.types +++ b/tests/baselines/reference/conditionalOperatorWithIdenticalBCT.types @@ -218,7 +218,7 @@ var result10: (t: X) => any = true ? (m) => m.propertyX1 : (n) => n.propertyX2; //Expr1 and Expr2 are literals var result11: any = true ? 1 : 'string'; >result11 : any ->true ? 1 : 'string' : 1 | "string" +>true ? 1 : 'string' : "string" | 1 >true : true >1 : 1 >'string' : "string" diff --git a/tests/baselines/reference/conditionalTypes1.types b/tests/baselines/reference/conditionalTypes1.types index 699808c1f7823..5b0cb6dd8383a 100644 --- a/tests/baselines/reference/conditionalTypes1.types +++ b/tests/baselines/reference/conditionalTypes1.types @@ -589,8 +589,8 @@ function zeroOf(value: T) { >>(typeof value === "number" ? 0 : typeof value === "string" ? "" : false) : ZeroOf >ZeroOf : ZeroOf >T : T ->(typeof value === "number" ? 0 : typeof value === "string" ? "" : false) : false | 0 | "" ->typeof value === "number" ? 0 : typeof value === "string" ? "" : false : false | 0 | "" +>(typeof value === "number" ? 0 : typeof value === "string" ? "" : false) : false | "" | 0 +>typeof value === "number" ? 0 : typeof value === "string" ? "" : false : false | "" | 0 >typeof value === "number" : boolean >typeof value : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function" >value : T diff --git a/tests/baselines/reference/declFileTypeAnnotationParenType.types b/tests/baselines/reference/declFileTypeAnnotationParenType.types index a73c9bba0a95a..9d8fddb0559af 100644 --- a/tests/baselines/reference/declFileTypeAnnotationParenType.types +++ b/tests/baselines/reference/declFileTypeAnnotationParenType.types @@ -24,7 +24,7 @@ var y = [() => new c()]; var k: (() => c) | string = (() => new c()) || ""; >k : string | (() => c) >c : c ->(() => new c()) || "" : (() => c) | "" +>(() => new c()) || "" : "" | (() => c) >(() => new c()) : () => c >() => new c() : () => c >new c() : c diff --git a/tests/baselines/reference/literalTypeWidening.js b/tests/baselines/reference/literalTypeWidening.js index 580021235575a..fc805ac670646 100644 --- a/tests/baselines/reference/literalTypeWidening.js +++ b/tests/baselines/reference/literalTypeWidening.js @@ -60,6 +60,18 @@ function f5() { let v4 = c4; } +declare function widening(x: T): T; +declare function nonWidening(x: T): T; + +function f6(cond: boolean) { + let x1 = widening('a'); + let x2 = widening(10); + let x3 = widening(cond ? 'a' : 10); + let y1 = nonWidening('a'); + let y2 = nonWidening(10); + let y3 = nonWidening(cond ? 'a' : 10); +} + // Repro from #10898 type FAILURE = "FAILURE"; @@ -95,10 +107,33 @@ type TestEvent = "onmouseover" | "onmouseout"; function onMouseOver(): TestEvent { return "onmouseover"; } -let x = onMouseOver(); +let x = onMouseOver(); + +// Repro from #23649 + +export function Set(...keys: K[]): Record { + const result = {} as Record + keys.forEach(key => result[key] = true) + return result +} + +export function keys(obj: Record): K[] { + return Object.keys(obj) as K[] +} + +type Obj = { code: LangCode } + +const langCodeSet = Set('fr', 'en', 'es', 'it', 'nl') +export type LangCode = keyof typeof langCodeSet +export const langCodes = keys(langCodeSet) + +const arr: Obj[] = langCodes.map(code => ({ code })) + //// [literalTypeWidening.js] +"use strict"; // Widening vs. non-widening literal types +exports.__esModule = true; function f1() { var c1 = "hello"; // Widening type "hello" var v1 = c1; // Type string @@ -153,6 +188,14 @@ function f5() { var c4 = "foo"; var v4 = c4; } +function f6(cond) { + var x1 = widening('a'); + var x2 = widening(10); + var x3 = widening(cond ? 'a' : 10); + var y1 = nonWidening('a'); + var y2 = nonWidening(10); + var y3 = nonWidening(cond ? 'a' : 10); +} var FAILURE = "FAILURE"; function doWork() { return FAILURE; @@ -172,3 +215,21 @@ if (isSuccess(result)) { } function onMouseOver() { return "onmouseover"; } var x = onMouseOver(); +// Repro from #23649 +function Set() { + var keys = []; + for (var _i = 0; _i < arguments.length; _i++) { + keys[_i] = arguments[_i]; + } + var result = {}; + keys.forEach(function (key) { return result[key] = true; }); + return result; +} +exports.Set = Set; +function keys(obj) { + return Object.keys(obj); +} +exports.keys = keys; +var langCodeSet = Set('fr', 'en', 'es', 'it', 'nl'); +exports.langCodes = keys(langCodeSet); +var arr = exports.langCodes.map(function (code) { return ({ code: code }); }); diff --git a/tests/baselines/reference/literalTypeWidening.symbols b/tests/baselines/reference/literalTypeWidening.symbols index e0da630180eaf..bb5a27026c2ab 100644 --- a/tests/baselines/reference/literalTypeWidening.symbols +++ b/tests/baselines/reference/literalTypeWidening.symbols @@ -197,89 +197,206 @@ function f5() { >c4 : Symbol(c4, Decl(literalTypeWidening.ts, 57, 9)) } +declare function widening(x: T): T; +>widening : Symbol(widening, Decl(literalTypeWidening.ts, 59, 1)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 61, 26)) +>x : Symbol(x, Decl(literalTypeWidening.ts, 61, 29)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 61, 26)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 61, 26)) + +declare function nonWidening(x: T): T; +>nonWidening : Symbol(nonWidening, Decl(literalTypeWidening.ts, 61, 38)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 62, 29)) +>x : Symbol(x, Decl(literalTypeWidening.ts, 62, 65)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 62, 29)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 62, 29)) + +function f6(cond: boolean) { +>f6 : Symbol(f6, Decl(literalTypeWidening.ts, 62, 74)) +>cond : Symbol(cond, Decl(literalTypeWidening.ts, 64, 12)) + + let x1 = widening('a'); +>x1 : Symbol(x1, Decl(literalTypeWidening.ts, 65, 7)) +>widening : Symbol(widening, Decl(literalTypeWidening.ts, 59, 1)) + + let x2 = widening(10); +>x2 : Symbol(x2, Decl(literalTypeWidening.ts, 66, 7)) +>widening : Symbol(widening, Decl(literalTypeWidening.ts, 59, 1)) + + let x3 = widening(cond ? 'a' : 10); +>x3 : Symbol(x3, Decl(literalTypeWidening.ts, 67, 7)) +>widening : Symbol(widening, Decl(literalTypeWidening.ts, 59, 1)) +>cond : Symbol(cond, Decl(literalTypeWidening.ts, 64, 12)) + + let y1 = nonWidening('a'); +>y1 : Symbol(y1, Decl(literalTypeWidening.ts, 68, 7)) +>nonWidening : Symbol(nonWidening, Decl(literalTypeWidening.ts, 61, 38)) + + let y2 = nonWidening(10); +>y2 : Symbol(y2, Decl(literalTypeWidening.ts, 69, 7)) +>nonWidening : Symbol(nonWidening, Decl(literalTypeWidening.ts, 61, 38)) + + let y3 = nonWidening(cond ? 'a' : 10); +>y3 : Symbol(y3, Decl(literalTypeWidening.ts, 70, 7)) +>nonWidening : Symbol(nonWidening, Decl(literalTypeWidening.ts, 61, 38)) +>cond : Symbol(cond, Decl(literalTypeWidening.ts, 64, 12)) +} + // Repro from #10898 type FAILURE = "FAILURE"; ->FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 59, 1), Decl(literalTypeWidening.ts, 64, 5)) +>FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 71, 1), Decl(literalTypeWidening.ts, 76, 5)) const FAILURE = "FAILURE"; ->FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 59, 1), Decl(literalTypeWidening.ts, 64, 5)) +>FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 71, 1), Decl(literalTypeWidening.ts, 76, 5)) type Result = T | FAILURE; ->Result : Symbol(Result, Decl(literalTypeWidening.ts, 64, 26)) ->T : Symbol(T, Decl(literalTypeWidening.ts, 66, 12)) ->T : Symbol(T, Decl(literalTypeWidening.ts, 66, 12)) ->FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 59, 1), Decl(literalTypeWidening.ts, 64, 5)) +>Result : Symbol(Result, Decl(literalTypeWidening.ts, 76, 26)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 78, 12)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 78, 12)) +>FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 71, 1), Decl(literalTypeWidening.ts, 76, 5)) function doWork(): Result { ->doWork : Symbol(doWork, Decl(literalTypeWidening.ts, 66, 29)) ->T : Symbol(T, Decl(literalTypeWidening.ts, 68, 16)) ->Result : Symbol(Result, Decl(literalTypeWidening.ts, 64, 26)) ->T : Symbol(T, Decl(literalTypeWidening.ts, 68, 16)) +>doWork : Symbol(doWork, Decl(literalTypeWidening.ts, 78, 29)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 80, 16)) +>Result : Symbol(Result, Decl(literalTypeWidening.ts, 76, 26)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 80, 16)) return FAILURE; ->FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 59, 1), Decl(literalTypeWidening.ts, 64, 5)) +>FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 71, 1), Decl(literalTypeWidening.ts, 76, 5)) } function isSuccess(result: Result): result is T { ->isSuccess : Symbol(isSuccess, Decl(literalTypeWidening.ts, 70, 1)) ->T : Symbol(T, Decl(literalTypeWidening.ts, 72, 19)) ->result : Symbol(result, Decl(literalTypeWidening.ts, 72, 22)) ->Result : Symbol(Result, Decl(literalTypeWidening.ts, 64, 26)) ->T : Symbol(T, Decl(literalTypeWidening.ts, 72, 19)) ->result : Symbol(result, Decl(literalTypeWidening.ts, 72, 22)) ->T : Symbol(T, Decl(literalTypeWidening.ts, 72, 19)) +>isSuccess : Symbol(isSuccess, Decl(literalTypeWidening.ts, 82, 1)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 84, 19)) +>result : Symbol(result, Decl(literalTypeWidening.ts, 84, 22)) +>Result : Symbol(Result, Decl(literalTypeWidening.ts, 76, 26)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 84, 19)) +>result : Symbol(result, Decl(literalTypeWidening.ts, 84, 22)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 84, 19)) return !isFailure(result); ->isFailure : Symbol(isFailure, Decl(literalTypeWidening.ts, 74, 1)) ->result : Symbol(result, Decl(literalTypeWidening.ts, 72, 22)) +>isFailure : Symbol(isFailure, Decl(literalTypeWidening.ts, 86, 1)) +>result : Symbol(result, Decl(literalTypeWidening.ts, 84, 22)) } function isFailure(result: Result): result is FAILURE { ->isFailure : Symbol(isFailure, Decl(literalTypeWidening.ts, 74, 1)) ->T : Symbol(T, Decl(literalTypeWidening.ts, 76, 19)) ->result : Symbol(result, Decl(literalTypeWidening.ts, 76, 22)) ->Result : Symbol(Result, Decl(literalTypeWidening.ts, 64, 26)) ->T : Symbol(T, Decl(literalTypeWidening.ts, 76, 19)) ->result : Symbol(result, Decl(literalTypeWidening.ts, 76, 22)) ->FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 59, 1), Decl(literalTypeWidening.ts, 64, 5)) +>isFailure : Symbol(isFailure, Decl(literalTypeWidening.ts, 86, 1)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 88, 19)) +>result : Symbol(result, Decl(literalTypeWidening.ts, 88, 22)) +>Result : Symbol(Result, Decl(literalTypeWidening.ts, 76, 26)) +>T : Symbol(T, Decl(literalTypeWidening.ts, 88, 19)) +>result : Symbol(result, Decl(literalTypeWidening.ts, 88, 22)) +>FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 71, 1), Decl(literalTypeWidening.ts, 76, 5)) return result === FAILURE; ->result : Symbol(result, Decl(literalTypeWidening.ts, 76, 22)) ->FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 59, 1), Decl(literalTypeWidening.ts, 64, 5)) +>result : Symbol(result, Decl(literalTypeWidening.ts, 88, 22)) +>FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 71, 1), Decl(literalTypeWidening.ts, 76, 5)) } function increment(x: number): number { ->increment : Symbol(increment, Decl(literalTypeWidening.ts, 78, 1)) ->x : Symbol(x, Decl(literalTypeWidening.ts, 80, 19)) +>increment : Symbol(increment, Decl(literalTypeWidening.ts, 90, 1)) +>x : Symbol(x, Decl(literalTypeWidening.ts, 92, 19)) return x + 1; ->x : Symbol(x, Decl(literalTypeWidening.ts, 80, 19)) +>x : Symbol(x, Decl(literalTypeWidening.ts, 92, 19)) } let result = doWork(); ->result : Symbol(result, Decl(literalTypeWidening.ts, 84, 3)) ->doWork : Symbol(doWork, Decl(literalTypeWidening.ts, 66, 29)) +>result : Symbol(result, Decl(literalTypeWidening.ts, 96, 3)) +>doWork : Symbol(doWork, Decl(literalTypeWidening.ts, 78, 29)) if (isSuccess(result)) { ->isSuccess : Symbol(isSuccess, Decl(literalTypeWidening.ts, 70, 1)) ->result : Symbol(result, Decl(literalTypeWidening.ts, 84, 3)) +>isSuccess : Symbol(isSuccess, Decl(literalTypeWidening.ts, 82, 1)) +>result : Symbol(result, Decl(literalTypeWidening.ts, 96, 3)) increment(result); ->increment : Symbol(increment, Decl(literalTypeWidening.ts, 78, 1)) ->result : Symbol(result, Decl(literalTypeWidening.ts, 84, 3)) +>increment : Symbol(increment, Decl(literalTypeWidening.ts, 90, 1)) +>result : Symbol(result, Decl(literalTypeWidening.ts, 96, 3)) } // Repro from #10898 type TestEvent = "onmouseover" | "onmouseout"; ->TestEvent : Symbol(TestEvent, Decl(literalTypeWidening.ts, 88, 1)) +>TestEvent : Symbol(TestEvent, Decl(literalTypeWidening.ts, 100, 1)) function onMouseOver(): TestEvent { return "onmouseover"; } ->onMouseOver : Symbol(onMouseOver, Decl(literalTypeWidening.ts, 92, 46)) ->TestEvent : Symbol(TestEvent, Decl(literalTypeWidening.ts, 88, 1)) +>onMouseOver : Symbol(onMouseOver, Decl(literalTypeWidening.ts, 104, 46)) +>TestEvent : Symbol(TestEvent, Decl(literalTypeWidening.ts, 100, 1)) let x = onMouseOver(); ->x : Symbol(x, Decl(literalTypeWidening.ts, 96, 3)) ->onMouseOver : Symbol(onMouseOver, Decl(literalTypeWidening.ts, 92, 46)) +>x : Symbol(x, Decl(literalTypeWidening.ts, 108, 3)) +>onMouseOver : Symbol(onMouseOver, Decl(literalTypeWidening.ts, 104, 46)) + +// Repro from #23649 + +export function Set(...keys: K[]): Record { +>Set : Symbol(Set, Decl(literalTypeWidening.ts, 108, 22)) +>K : Symbol(K, Decl(literalTypeWidening.ts, 112, 20)) +>keys : Symbol(keys, Decl(literalTypeWidening.ts, 112, 38)) +>K : Symbol(K, Decl(literalTypeWidening.ts, 112, 20)) +>Record : Symbol(Record, Decl(lib.d.ts, --, --)) +>K : Symbol(K, Decl(literalTypeWidening.ts, 112, 20)) + + const result = {} as Record +>result : Symbol(result, Decl(literalTypeWidening.ts, 113, 7)) +>Record : Symbol(Record, Decl(lib.d.ts, --, --)) +>K : Symbol(K, Decl(literalTypeWidening.ts, 112, 20)) + + keys.forEach(key => result[key] = true) +>keys.forEach : Symbol(Array.forEach, Decl(lib.d.ts, --, --)) +>keys : Symbol(keys, Decl(literalTypeWidening.ts, 112, 38)) +>forEach : Symbol(Array.forEach, Decl(lib.d.ts, --, --)) +>key : Symbol(key, Decl(literalTypeWidening.ts, 114, 15)) +>result : Symbol(result, Decl(literalTypeWidening.ts, 113, 7)) +>key : Symbol(key, Decl(literalTypeWidening.ts, 114, 15)) + + return result +>result : Symbol(result, Decl(literalTypeWidening.ts, 113, 7)) +} + +export function keys(obj: Record): K[] { +>keys : Symbol(keys, Decl(literalTypeWidening.ts, 116, 1)) +>K : Symbol(K, Decl(literalTypeWidening.ts, 118, 21)) +>V : Symbol(V, Decl(literalTypeWidening.ts, 118, 38)) +>obj : Symbol(obj, Decl(literalTypeWidening.ts, 118, 42)) +>Record : Symbol(Record, Decl(lib.d.ts, --, --)) +>K : Symbol(K, Decl(literalTypeWidening.ts, 118, 21)) +>V : Symbol(V, Decl(literalTypeWidening.ts, 118, 38)) +>K : Symbol(K, Decl(literalTypeWidening.ts, 118, 21)) + + return Object.keys(obj) as K[] +>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>keys : Symbol(ObjectConstructor.keys, Decl(lib.d.ts, --, --)) +>obj : Symbol(obj, Decl(literalTypeWidening.ts, 118, 42)) +>K : Symbol(K, Decl(literalTypeWidening.ts, 118, 21)) +} + +type Obj = { code: LangCode } +>Obj : Symbol(Obj, Decl(literalTypeWidening.ts, 120, 1)) +>code : Symbol(code, Decl(literalTypeWidening.ts, 122, 12)) +>LangCode : Symbol(LangCode, Decl(literalTypeWidening.ts, 124, 53)) + +const langCodeSet = Set('fr', 'en', 'es', 'it', 'nl') +>langCodeSet : Symbol(langCodeSet, Decl(literalTypeWidening.ts, 124, 5)) +>Set : Symbol(Set, Decl(literalTypeWidening.ts, 108, 22)) + +export type LangCode = keyof typeof langCodeSet +>LangCode : Symbol(LangCode, Decl(literalTypeWidening.ts, 124, 53)) +>langCodeSet : Symbol(langCodeSet, Decl(literalTypeWidening.ts, 124, 5)) + +export const langCodes = keys(langCodeSet) +>langCodes : Symbol(langCodes, Decl(literalTypeWidening.ts, 126, 12)) +>keys : Symbol(keys, Decl(literalTypeWidening.ts, 116, 1)) +>langCodeSet : Symbol(langCodeSet, Decl(literalTypeWidening.ts, 124, 5)) + +const arr: Obj[] = langCodes.map(code => ({ code })) +>arr : Symbol(arr, Decl(literalTypeWidening.ts, 128, 5)) +>Obj : Symbol(Obj, Decl(literalTypeWidening.ts, 120, 1)) +>langCodes.map : Symbol(Array.map, Decl(lib.d.ts, --, --)) +>langCodes : Symbol(langCodes, Decl(literalTypeWidening.ts, 126, 12)) +>map : Symbol(Array.map, Decl(lib.d.ts, --, --)) +>code : Symbol(code, Decl(literalTypeWidening.ts, 128, 33)) +>code : Symbol(code, Decl(literalTypeWidening.ts, 128, 43)) diff --git a/tests/baselines/reference/literalTypeWidening.types b/tests/baselines/reference/literalTypeWidening.types index db5df6ba90c7c..7d41472496a41 100644 --- a/tests/baselines/reference/literalTypeWidening.types +++ b/tests/baselines/reference/literalTypeWidening.types @@ -219,6 +219,67 @@ function f5() { >c4 : "foo" } +declare function widening(x: T): T; +>widening : (x: T) => T +>T : T +>x : T +>T : T +>T : T + +declare function nonWidening(x: T): T; +>nonWidening : (x: T) => T +>T : T +>x : T +>T : T +>T : T + +function f6(cond: boolean) { +>f6 : (cond: boolean) => void +>cond : boolean + + let x1 = widening('a'); +>x1 : string +>widening('a') : "a" +>widening : (x: T) => T +>'a' : "a" + + let x2 = widening(10); +>x2 : number +>widening(10) : 10 +>widening : (x: T) => T +>10 : 10 + + let x3 = widening(cond ? 'a' : 10); +>x3 : string | number +>widening(cond ? 'a' : 10) : "a" | 10 +>widening : (x: T) => T +>cond ? 'a' : 10 : "a" | 10 +>cond : boolean +>'a' : "a" +>10 : 10 + + let y1 = nonWidening('a'); +>y1 : "a" +>nonWidening('a') : "a" +>nonWidening : (x: T) => T +>'a' : "a" + + let y2 = nonWidening(10); +>y2 : 10 +>nonWidening(10) : 10 +>nonWidening : (x: T) => T +>10 : 10 + + let y3 = nonWidening(cond ? 'a' : 10); +>y3 : "a" | 10 +>nonWidening(cond ? 'a' : 10) : "a" | 10 +>nonWidening : (x: T) => T +>cond ? 'a' : 10 : "a" | 10 +>cond : boolean +>'a' : "a" +>10 : 10 +} + // Repro from #10898 type FAILURE = "FAILURE"; @@ -316,3 +377,97 @@ let x = onMouseOver(); >onMouseOver() : TestEvent >onMouseOver : () => TestEvent +// Repro from #23649 + +export function Set(...keys: K[]): Record { +>Set : (...keys: K[]) => Record +>K : K +>keys : K[] +>K : K +>Record : Record +>K : K +>true : true + + const result = {} as Record +>result : Record +>{} as Record : Record +>{} : {} +>Record : Record +>K : K +>true : true + + keys.forEach(key => result[key] = true) +>keys.forEach(key => result[key] = true) : void +>keys.forEach : (callbackfn: (value: K, index: number, array: K[]) => void, thisArg?: any) => void +>keys : K[] +>forEach : (callbackfn: (value: K, index: number, array: K[]) => void, thisArg?: any) => void +>key => result[key] = true : (key: K) => boolean +>key : K +>result[key] = true : true +>result[key] : Record[K] +>result : Record +>key : K +>true : true + + return result +>result : Record +} + +export function keys(obj: Record): K[] { +>keys : (obj: Record) => K[] +>K : K +>V : V +>obj : Record +>Record : Record +>K : K +>V : V +>K : K + + return Object.keys(obj) as K[] +>Object.keys(obj) as K[] : K[] +>Object.keys(obj) : string[] +>Object.keys : (o: {}) => string[] +>Object : ObjectConstructor +>keys : (o: {}) => string[] +>obj : Record +>K : K +} + +type Obj = { code: LangCode } +>Obj : Obj +>code : "fr" | "en" | "es" | "it" | "nl" +>LangCode : "fr" | "en" | "es" | "it" | "nl" + +const langCodeSet = Set('fr', 'en', 'es', 'it', 'nl') +>langCodeSet : Record<"fr" | "en" | "es" | "it" | "nl", true> +>Set('fr', 'en', 'es', 'it', 'nl') : Record<"fr" | "en" | "es" | "it" | "nl", true> +>Set : (...keys: K[]) => Record +>'fr' : "fr" +>'en' : "en" +>'es' : "es" +>'it' : "it" +>'nl' : "nl" + +export type LangCode = keyof typeof langCodeSet +>LangCode : "fr" | "en" | "es" | "it" | "nl" +>langCodeSet : Record<"fr" | "en" | "es" | "it" | "nl", true> + +export const langCodes = keys(langCodeSet) +>langCodes : ("fr" | "en" | "es" | "it" | "nl")[] +>keys(langCodeSet) : ("fr" | "en" | "es" | "it" | "nl")[] +>keys : (obj: Record) => K[] +>langCodeSet : Record<"fr" | "en" | "es" | "it" | "nl", true> + +const arr: Obj[] = langCodes.map(code => ({ code })) +>arr : Obj[] +>Obj : Obj +>langCodes.map(code => ({ code })) : { code: "fr" | "en" | "es" | "it" | "nl"; }[] +>langCodes.map : (callbackfn: (value: "fr" | "en" | "es" | "it" | "nl", index: number, array: ("fr" | "en" | "es" | "it" | "nl")[]) => U, thisArg?: any) => U[] +>langCodes : ("fr" | "en" | "es" | "it" | "nl")[] +>map : (callbackfn: (value: "fr" | "en" | "es" | "it" | "nl", index: number, array: ("fr" | "en" | "es" | "it" | "nl")[]) => U, thisArg?: any) => U[] +>code => ({ code }) : (code: "fr" | "en" | "es" | "it" | "nl") => { code: "fr" | "en" | "es" | "it" | "nl"; } +>code : "fr" | "en" | "es" | "it" | "nl" +>({ code }) : { code: "fr" | "en" | "es" | "it" | "nl"; } +>{ code } : { code: "fr" | "en" | "es" | "it" | "nl"; } +>code : "fr" | "en" | "es" | "it" | "nl" + diff --git a/tests/baselines/reference/literalTypes2.types b/tests/baselines/reference/literalTypes2.types index 429a1457c4e9f..e4e33445790d2 100644 --- a/tests/baselines/reference/literalTypes2.types +++ b/tests/baselines/reference/literalTypes2.types @@ -555,7 +555,7 @@ class C2 { >bar : () => 1 | 0 return cond ? 0 : 1; ->cond ? 0 : 1 : 1 | 0 +>cond ? 0 : 1 : 0 | 1 >cond : boolean >0 : 0 >1 : 1 diff --git a/tests/baselines/reference/literalTypes3.types b/tests/baselines/reference/literalTypes3.types index 059e2777e541e..c0623dd6523f5 100644 --- a/tests/baselines/reference/literalTypes3.types +++ b/tests/baselines/reference/literalTypes3.types @@ -107,7 +107,7 @@ function f5(x: number, y: 1 | 2) { >y : 1 | 2 x; // 0 | 1 | 2 ->x : 1 | 2 | 0 +>x : 0 | 1 | 2 } } @@ -126,7 +126,7 @@ function f6(x: number, y: 1 | 2) { >x : number x; // 0 | 1 | 2 ->x : 1 | 2 | 0 +>x : 0 | 1 | 2 } } diff --git a/tests/baselines/reference/newExpressionWithTypeParameterConstrainedToOuterTypeParameter.types b/tests/baselines/reference/newExpressionWithTypeParameterConstrainedToOuterTypeParameter.types index badd17765b8d2..6d54119880233 100644 --- a/tests/baselines/reference/newExpressionWithTypeParameterConstrainedToOuterTypeParameter.types +++ b/tests/baselines/reference/newExpressionWithTypeParameterConstrainedToOuterTypeParameter.types @@ -15,7 +15,7 @@ var i: I; >I : I var y = new i(""); // y should be string ->y : string +>y : "" >new i("") : "" >i : I >"" : "" diff --git a/tests/baselines/reference/parserArgumentList1.types b/tests/baselines/reference/parserArgumentList1.types index ddf00ee8750da..3e210b8089078 100644 --- a/tests/baselines/reference/parserArgumentList1.types +++ b/tests/baselines/reference/parserArgumentList1.types @@ -26,7 +26,7 @@ export function removeClass (node:HTMLElement, className:string) { >rightDelimiter : any return leftDelimiter.length + rightDelimiter.length === 2 ? ' ' : ''; ->leftDelimiter.length + rightDelimiter.length === 2 ? ' ' : '' : " " | "" +>leftDelimiter.length + rightDelimiter.length === 2 ? ' ' : '' : "" | " " >leftDelimiter.length + rightDelimiter.length === 2 : boolean >leftDelimiter.length + rightDelimiter.length : any >leftDelimiter.length : any diff --git a/tests/baselines/reference/subtypesOfTypeParameter.types b/tests/baselines/reference/subtypesOfTypeParameter.types index 58af856e15074..b703292fb4f2b 100644 --- a/tests/baselines/reference/subtypesOfTypeParameter.types +++ b/tests/baselines/reference/subtypesOfTypeParameter.types @@ -144,14 +144,14 @@ function f2(x: T, y: U) { var r2 = true ? '' : x; >r2 : string | T ->true ? '' : x : T | "" +>true ? '' : x : "" | T >true : true >'' : "" >x : T var r2 = true ? x : ''; >r2 : string | T ->true ? x : '' : T | "" +>true ? x : '' : "" | T >true : true >x : T >'' : "" diff --git a/tests/baselines/reference/subtypesOfTypeParameterWithConstraints2.types b/tests/baselines/reference/subtypesOfTypeParameterWithConstraints2.types index e2f294343a573..34ef257609b60 100644 --- a/tests/baselines/reference/subtypesOfTypeParameterWithConstraints2.types +++ b/tests/baselines/reference/subtypesOfTypeParameterWithConstraints2.types @@ -259,14 +259,14 @@ function f6(x: T) { var r2 = true ? '' : x; // ok >r2 : string | T ->true ? '' : x : T | "" +>true ? '' : x : "" | T >true : true >'' : "" >x : T var r2 = true ? x : ''; // ok >r2 : string | T ->true ? x : '' : T | "" +>true ? x : '' : "" | T >true : true >x : T >'' : "" diff --git a/tests/baselines/reference/uniqueSymbols.types b/tests/baselines/reference/uniqueSymbols.types index 55ce8d9c87ecb..3cae76bd7820b 100644 --- a/tests/baselines/reference/uniqueSymbols.types +++ b/tests/baselines/reference/uniqueSymbols.types @@ -699,19 +699,19 @@ g(N["s"]); // falsy expressions s || ""; ->s || "" : unique symbol | "" +>s || "" : "" | unique symbol >s : unique symbol >"" : "" N.s || ""; ->N.s || "" : unique symbol | "" +>N.s || "" : "" | unique symbol >N.s : unique symbol >N : typeof N >s : unique symbol >"" : "" N["s"] || ""; ->N["s"] || "" : unique symbol | "" +>N["s"] || "" : "" | unique symbol >N["s"] : unique symbol >N : typeof N >"s" : "s" diff --git a/tests/baselines/reference/uniqueSymbolsDeclarations.types b/tests/baselines/reference/uniqueSymbolsDeclarations.types index 6bfee5a040395..792a27f5182b5 100644 --- a/tests/baselines/reference/uniqueSymbolsDeclarations.types +++ b/tests/baselines/reference/uniqueSymbolsDeclarations.types @@ -699,19 +699,19 @@ g(N["s"]); // falsy expressions s || ""; ->s || "" : unique symbol | "" +>s || "" : "" | unique symbol >s : unique symbol >"" : "" N.s || ""; ->N.s || "" : unique symbol | "" +>N.s || "" : "" | unique symbol >N.s : unique symbol >N : typeof N >s : unique symbol >"" : "" N["s"] || ""; ->N["s"] || "" : unique symbol | "" +>N["s"] || "" : "" | unique symbol >N["s"] : unique symbol >N : typeof N >"s" : "s" diff --git a/tests/cases/conformance/types/literal/literalTypeWidening.ts b/tests/cases/conformance/types/literal/literalTypeWidening.ts index 98ed328f0d27d..4c818793142b1 100644 --- a/tests/cases/conformance/types/literal/literalTypeWidening.ts +++ b/tests/cases/conformance/types/literal/literalTypeWidening.ts @@ -59,6 +59,18 @@ function f5() { let v4 = c4; } +declare function widening(x: T): T; +declare function nonWidening(x: T): T; + +function f6(cond: boolean) { + let x1 = widening('a'); + let x2 = widening(10); + let x3 = widening(cond ? 'a' : 10); + let y1 = nonWidening('a'); + let y2 = nonWidening(10); + let y3 = nonWidening(cond ? 'a' : 10); +} + // Repro from #10898 type FAILURE = "FAILURE"; @@ -94,4 +106,24 @@ type TestEvent = "onmouseover" | "onmouseout"; function onMouseOver(): TestEvent { return "onmouseover"; } -let x = onMouseOver(); \ No newline at end of file +let x = onMouseOver(); + +// Repro from #23649 + +export function Set(...keys: K[]): Record { + const result = {} as Record + keys.forEach(key => result[key] = true) + return result +} + +export function keys(obj: Record): K[] { + return Object.keys(obj) as K[] +} + +type Obj = { code: LangCode } + +const langCodeSet = Set('fr', 'en', 'es', 'it', 'nl') +export type LangCode = keyof typeof langCodeSet +export const langCodes = keys(langCodeSet) + +const arr: Obj[] = langCodes.map(code => ({ code }))