diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cb373b4375f20..042d9f253e83c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6092,6 +6092,27 @@ namespace ts { return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type)); } + function createStringLiteralApparentProperties(type: StringLiteralType): Type { + const propTable = createSymbolTable(); + const possibleMembers: Type[] = []; + for (let i = 0; i < type.value.length; i++) { + const propName = "" + i as __String; + const prop = createSymbol(SymbolFlags.Property, propName); + prop.type = getLiteralType(type.value[i]); + propTable.set(propName, prop); + possibleMembers.push(prop.type); + } + if (strictNullChecks) { + possibleMembers.push(undefinedType); + } + copyEntries(resolveStructuredTypeMembers(globalStringType).members, propTable); + return createAnonymousType(type.symbol, propTable, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, createIndexInfo(getUnionType(possibleMembers), /*isReadonly*/ true)); + } + + function getStringLiteralApparentProperties(type: StringLiteralType) { + return type.resolvedApparentType || (type.resolvedApparentType = createStringLiteralApparentProperties(type)); + } + function getResolvedTypeParameterDefault(typeParameter: TypeParameter): Type | undefined { if (!typeParameter.default) { if (typeParameter.target) { @@ -6147,6 +6168,7 @@ namespace ts { function getApparentType(type: Type): Type { const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type; return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t) : + t.flags & TypeFlags.StringLiteral ? getStringLiteralApparentProperties(t as StringLiteralType) : t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : t.flags & TypeFlags.BooleanLike ? globalBooleanType : diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1874821727c88..844397a2c2296 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3347,6 +3347,7 @@ namespace ts { export interface StringLiteralType extends LiteralType { value: string; + /*@internal*/ resolvedApparentType?: Type; // Cached generated apparent properties } export interface NumberLiteralType extends LiteralType { diff --git a/tests/baselines/reference/arrayLiteralContextualLiteralUnion.js b/tests/baselines/reference/arrayLiteralContextualLiteralUnion.js new file mode 100644 index 0000000000000..6affed0c5e219 --- /dev/null +++ b/tests/baselines/reference/arrayLiteralContextualLiteralUnion.js @@ -0,0 +1,5 @@ +//// [arrayLiteralContextualLiteralUnion.ts] +const x: 'a' | 'a'[] = ['a']; + +//// [arrayLiteralContextualLiteralUnion.js] +var x = ['a']; diff --git a/tests/baselines/reference/arrayLiteralContextualLiteralUnion.symbols b/tests/baselines/reference/arrayLiteralContextualLiteralUnion.symbols new file mode 100644 index 0000000000000..e8003f72391a7 --- /dev/null +++ b/tests/baselines/reference/arrayLiteralContextualLiteralUnion.symbols @@ -0,0 +1,4 @@ +=== tests/cases/compiler/arrayLiteralContextualLiteralUnion.ts === +const x: 'a' | 'a'[] = ['a']; +>x : Symbol(x, Decl(arrayLiteralContextualLiteralUnion.ts, 0, 5)) + diff --git a/tests/baselines/reference/arrayLiteralContextualLiteralUnion.types b/tests/baselines/reference/arrayLiteralContextualLiteralUnion.types new file mode 100644 index 0000000000000..08925f765df1a --- /dev/null +++ b/tests/baselines/reference/arrayLiteralContextualLiteralUnion.types @@ -0,0 +1,6 @@ +=== tests/cases/compiler/arrayLiteralContextualLiteralUnion.ts === +const x: 'a' | 'a'[] = ['a']; +>x : "a" | "a"[] +>['a'] : ["a"] +>'a' : "a" + diff --git a/tests/baselines/reference/defaultIndexProps2.symbols b/tests/baselines/reference/defaultIndexProps2.symbols index 5c9880c55f307..e6e2b46c13408 100644 --- a/tests/baselines/reference/defaultIndexProps2.symbols +++ b/tests/baselines/reference/defaultIndexProps2.symbols @@ -21,4 +21,5 @@ var o = {v:"Yo2"}; 1[0]; var q = "s"[0]; >q : Symbol(q, Decl(defaultIndexProps2.ts, 13, 3)) +>0 : Symbol(0) diff --git a/tests/baselines/reference/defaultIndexProps2.types b/tests/baselines/reference/defaultIndexProps2.types index a50e4af450e56..b44bc9db0d729 100644 --- a/tests/baselines/reference/defaultIndexProps2.types +++ b/tests/baselines/reference/defaultIndexProps2.types @@ -28,8 +28,8 @@ var o = {v:"Yo2"}; >0 : 0 var q = "s"[0]; ->q : string ->"s"[0] : string +>q : "s" +>"s"[0] : "s" >"s" : "s" >0 : 0 diff --git a/tests/baselines/reference/keyofAndIndexedAccessErrors.types b/tests/baselines/reference/keyofAndIndexedAccessErrors.types index 4d2e25641d39d..3042919385351 100644 --- a/tests/baselines/reference/keyofAndIndexedAccessErrors.types +++ b/tests/baselines/reference/keyofAndIndexedAccessErrors.types @@ -30,23 +30,23 @@ type T01 = keyof Object; >Object : Object type T02 = keyof keyof Object; ->T02 : "length" | "toString" | "valueOf" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "substr" +>T02 : "length" | "toString" | "valueOf" | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "substr" >Object : Object type T03 = keyof keyof keyof Object; ->T03 : "length" | "toString" | "valueOf" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "substr" +>T03 : "length" | "toString" | "valueOf" | "0" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "substr" >Object : Object type T04 = keyof keyof keyof keyof Object; ->T04 : "length" | "toString" | "valueOf" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "substr" +>T04 : "length" | "toString" | "valueOf" | "0" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "substr" >Object : Object type T05 = keyof keyof keyof keyof keyof Object; ->T05 : "length" | "toString" | "valueOf" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "substr" +>T05 : "length" | "toString" | "valueOf" | "0" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "substr" >Object : Object type T06 = keyof keyof keyof keyof keyof keyof Object; ->T06 : "length" | "toString" | "valueOf" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "substr" +>T06 : "length" | "toString" | "valueOf" | "0" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "substr" >Object : Object type T10 = Shape["name"]; diff --git a/tests/baselines/reference/stringHasStringValuedNumericIndexer.types b/tests/baselines/reference/stringHasStringValuedNumericIndexer.types index 01f086ebbf434..c111100a27984 100644 --- a/tests/baselines/reference/stringHasStringValuedNumericIndexer.types +++ b/tests/baselines/reference/stringHasStringValuedNumericIndexer.types @@ -1,7 +1,7 @@ === tests/cases/compiler/stringHasStringValuedNumericIndexer.ts === var str: string = ""[0]; >str : string ->""[0] : string +>""[0] : never >"" : "" >0 : 0 diff --git a/tests/cases/compiler/arrayLiteralContextualLiteralUnion.ts b/tests/cases/compiler/arrayLiteralContextualLiteralUnion.ts new file mode 100644 index 0000000000000..31bd9ab74ad15 --- /dev/null +++ b/tests/cases/compiler/arrayLiteralContextualLiteralUnion.ts @@ -0,0 +1 @@ +const x: 'a' | 'a'[] = ['a']; \ No newline at end of file