diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2ae303af37a95..66d2ce14828c8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10605,6 +10605,13 @@ namespace ts { } function checkStringLiteralExpression(node: StringLiteral): Type { + const parentKind = node.parent.kind; + if (parentKind === SyntaxKind.VariableDeclaration || parentKind === SyntaxKind.BindingElement) { + if (getCombinedNodeFlags(node.parent) & NodeFlags.Const) { + return getStringLiteralTypeForText(node.text); + } + } + const contextualType = getContextualType(node); if (contextualType && contextualTypeIsStringLiteralType(contextualType)) { return getStringLiteralTypeForText(node.text); diff --git a/src/services/services.ts b/src/services/services.ts index 7c98e650a16c9..75e02a8e6de11 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1581,6 +1581,36 @@ namespace ts { export const letElement = "let"; } + export type ScriptElementKind = typeof ScriptElementKind.alias + | typeof ScriptElementKind.callSignatureElement + | typeof ScriptElementKind.classElement + | typeof ScriptElementKind.constElement + | typeof ScriptElementKind.constructorImplementationElement + | typeof ScriptElementKind.constructSignatureElement + | typeof ScriptElementKind.enumElement + | typeof ScriptElementKind.functionElement + | typeof ScriptElementKind.indexSignatureElement + | typeof ScriptElementKind.interfaceElement + | typeof ScriptElementKind.keyword + | typeof ScriptElementKind.label + | typeof ScriptElementKind.letElement + | typeof ScriptElementKind.localClassElement + | typeof ScriptElementKind.localFunctionElement + | typeof ScriptElementKind.localVariableElement + | typeof ScriptElementKind.memberFunctionElement + | typeof ScriptElementKind.memberGetAccessorElement + | typeof ScriptElementKind.memberSetAccessorElement + | typeof ScriptElementKind.memberVariableElement + | typeof ScriptElementKind.moduleElement + | typeof ScriptElementKind.parameterElement + | typeof ScriptElementKind.primitiveType + | typeof ScriptElementKind.scriptElement + | typeof ScriptElementKind.typeElement + | typeof ScriptElementKind.typeParameterElement + | typeof ScriptElementKind.unknown + | typeof ScriptElementKind.variableElement + | typeof ScriptElementKind.warning; + export module ScriptElementKindModifier { export const none = ""; export const publicMemberModifier = "public"; @@ -3967,7 +3997,7 @@ namespace ts { } // TODO(drosen): use contextual SemanticMeaning. - function getSymbolKind(symbol: Symbol, location: Node): string { + function getSymbolKind(symbol: Symbol, location: Node): ScriptElementKind { let flags = symbol.getFlags(); if (flags & SymbolFlags.Class) return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ? @@ -3988,7 +4018,7 @@ namespace ts { return result; } - function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags, location: Node) { + function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags, location: Node): ScriptElementKind { let typeChecker = program.getTypeChecker(); if (typeChecker.isUndefinedSymbol(symbol)) { diff --git a/tests/baselines/reference/constDeclarations-es5.types b/tests/baselines/reference/constDeclarations-es5.types index a897c3f9cd0f1..db15974391824 100644 --- a/tests/baselines/reference/constDeclarations-es5.types +++ b/tests/baselines/reference/constDeclarations-es5.types @@ -12,7 +12,7 @@ const z9 = 0, z10 :string = "", z11 = null; >z9 : number >0 : number >z10 : string ->"" : string +>"" : "" >z11 : any >null : null diff --git a/tests/baselines/reference/constDeclarations-scopes2.types b/tests/baselines/reference/constDeclarations-scopes2.types index a6bbdee7612ac..56813956af7d6 100644 --- a/tests/baselines/reference/constDeclarations-scopes2.types +++ b/tests/baselines/reference/constDeclarations-scopes2.types @@ -2,8 +2,8 @@ // global const c = "string"; ->c : string ->"string" : string +>c : "string" +>"string" : "string" var n: number; >n : number diff --git a/tests/baselines/reference/constDeclarations.types b/tests/baselines/reference/constDeclarations.types index efdc534ef1ca0..e93699fe5fb10 100644 --- a/tests/baselines/reference/constDeclarations.types +++ b/tests/baselines/reference/constDeclarations.types @@ -13,7 +13,7 @@ const c3 = 0, c4 :string = "", c5 = null; >c3 : number >0 : number >c4 : string ->"" : string +>"" : "" >c5 : any >null : null diff --git a/tests/baselines/reference/constDeclarations2.types b/tests/baselines/reference/constDeclarations2.types index f8184b8f8e033..572db987d107a 100644 --- a/tests/baselines/reference/constDeclarations2.types +++ b/tests/baselines/reference/constDeclarations2.types @@ -16,7 +16,7 @@ module M { >c3 : number >0 : number >c4 : string ->"" : string +>"" : "" >c5 : any >null : null } diff --git a/tests/baselines/reference/downlevelLetConst13.types b/tests/baselines/reference/downlevelLetConst13.types index 0453d3a6ad376..fa6a99c4d2335 100644 --- a/tests/baselines/reference/downlevelLetConst13.types +++ b/tests/baselines/reference/downlevelLetConst13.types @@ -10,8 +10,8 @@ export let foo = 10; >10 : number export const bar = "123" ->bar : string ->"123" : string +>bar : "123" +>"123" : "123" export let [bar1] = [1]; >bar1 : number diff --git a/tests/baselines/reference/downlevelLetConst15.types b/tests/baselines/reference/downlevelLetConst15.types index 72b29e3fe6680..e6c76a404afe0 100644 --- a/tests/baselines/reference/downlevelLetConst15.types +++ b/tests/baselines/reference/downlevelLetConst15.types @@ -108,8 +108,8 @@ var y = true; >true : boolean { const y = ""; ->y : string ->"" : string +>y : "" +>"" : "" const [z6] = [true] >z6 : boolean @@ -140,7 +140,7 @@ var y = true; use(y); >use(y) : any >use : (a: any) => any ->y : string +>y : "" use(z6); >use(z6) : any @@ -166,8 +166,8 @@ var z5 = 1; >1 : number { const z = ""; ->z : string ->"" : string +>z : "" +>"" : "" const [z5] = [5]; >z5 : number @@ -194,7 +194,7 @@ var z5 = 1; use(z); >use(z) : any >use : (a: any) => any ->z : string +>z : "" } use(y); >use(y) : any diff --git a/tests/baselines/reference/es6ModuleConst.types b/tests/baselines/reference/es6ModuleConst.types index 99b9f7c298046..b83e39e61ad1f 100644 --- a/tests/baselines/reference/es6ModuleConst.types +++ b/tests/baselines/reference/es6ModuleConst.types @@ -1,11 +1,11 @@ === tests/cases/compiler/es6ModuleConst.ts === export const a = "hello"; ->a : string ->"hello" : string +>a : "hello" +>"hello" : "hello" export const x: string = a, y = x; >x : string ->a : string +>a : "hello" >y : string >x : string @@ -23,49 +23,49 @@ export module m1 { >m1 : typeof m1 export const k = a; ->k : string ->a : string +>k : "hello" +>a : "hello" export const l: string = b, m = k; >l : string >b : string ->m : string ->k : string +>m : "hello" +>k : "hello" const n = m1.k; ->n : string ->m1.k : string +>n : "hello" +>m1.k : "hello" >m1 : typeof m1 ->k : string +>k : "hello" const o: string = n, p = k; >o : string ->n : string ->p : string ->k : string +>n : "hello" +>p : "hello" +>k : "hello" } module m2 { >m2 : typeof m2 export const k = a; ->k : string ->a : string +>k : "hello" +>a : "hello" export const l: string = b, m = k; >l : string >b : string ->m : string ->k : string +>m : "hello" +>k : "hello" const n = m1.k; ->n : string ->m1.k : string +>n : "hello" +>m1.k : "hello" >m1 : typeof m1 ->k : string +>k : "hello" const o: string = n, p = k; >o : string ->n : string ->p : string ->k : string +>n : "hello" +>p : "hello" +>k : "hello" } diff --git a/tests/baselines/reference/stringLiteralValueInConstDecl01.errors.txt b/tests/baselines/reference/stringLiteralValueInConstDecl01.errors.txt new file mode 100644 index 0000000000000..c8d7d4daf5294 --- /dev/null +++ b/tests/baselines/reference/stringLiteralValueInConstDecl01.errors.txt @@ -0,0 +1,10 @@ +tests/cases/compiler/stringLiteralValueInConstDecl01.ts(4,1): error TS2322: Type '"bar"' is not assignable to type '"foo"'. + + +==== tests/cases/compiler/stringLiteralValueInConstDecl01.ts (1 errors) ==== + + const foo = "foo"; + var bar = foo; + bar = "bar"; + ~~~ +!!! error TS2322: Type '"bar"' is not assignable to type '"foo"'. \ No newline at end of file diff --git a/tests/baselines/reference/stringLiteralValueInConstDecl01.js b/tests/baselines/reference/stringLiteralValueInConstDecl01.js new file mode 100644 index 0000000000000..5fa31f1681fb9 --- /dev/null +++ b/tests/baselines/reference/stringLiteralValueInConstDecl01.js @@ -0,0 +1,10 @@ +//// [stringLiteralValueInConstDecl01.ts] + +const foo = "foo"; +var bar = foo; +bar = "bar"; + +//// [stringLiteralValueInConstDecl01.js] +var foo = "foo"; +var bar = foo; +bar = "bar"; diff --git a/tests/baselines/reference/stringLiteralValueInConstDecl02.errors.txt b/tests/baselines/reference/stringLiteralValueInConstDecl02.errors.txt new file mode 100644 index 0000000000000..ec1b685a80e3f --- /dev/null +++ b/tests/baselines/reference/stringLiteralValueInConstDecl02.errors.txt @@ -0,0 +1,26 @@ +error TS1204: Cannot compile modules into 'es2015' when targeting 'ES5' or lower. +tests/cases/compiler/stringLiteralValueInConstDecl02.ts(7,17): error TS2354: No best common type exists among return expressions. + + +!!! error TS1204: Cannot compile modules into 'es2015' when targeting 'ES5' or lower. +==== tests/cases/compiler/stringLiteralValueInConstDecl02.ts (1 errors) ==== + + const foo = "foo"; + const bar = "bar"; + + declare function randBool(): boolean; + + export function fooOrBar1() { + ~~~~~~~~~ +!!! error TS2354: No best common type exists among return expressions. + if (randBool()) { + return foo; + } + else { + return bar; + } + } + + export function fooOrBar2() { + return randBool() ? foo : bar; + } \ No newline at end of file diff --git a/tests/baselines/reference/stringLiteralValueInConstDecl02.js b/tests/baselines/reference/stringLiteralValueInConstDecl02.js new file mode 100644 index 0000000000000..3397ec5f3a679 --- /dev/null +++ b/tests/baselines/reference/stringLiteralValueInConstDecl02.js @@ -0,0 +1,34 @@ +//// [stringLiteralValueInConstDecl02.ts] + +const foo = "foo"; +const bar = "bar"; + +declare function randBool(): boolean; + +export function fooOrBar1() { + if (randBool()) { + return foo; + } + else { + return bar; + } +} + +export function fooOrBar2() { + return randBool() ? foo : bar; +} + +//// [stringLiteralValueInConstDecl02.js] +var foo = "foo"; +var bar = "bar"; +export function fooOrBar1() { + if (randBool()) { + return foo; + } + else { + return bar; + } +} +export function fooOrBar2() { + return randBool() ? foo : bar; +} diff --git a/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl01.js b/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl01.js new file mode 100644 index 0000000000000..5f596ac8f2795 --- /dev/null +++ b/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl01.js @@ -0,0 +1,15 @@ +//// [stringLiteralValueInDestructuredConstDecl01.ts] + +const {a: {b = "foo"}} = { + a: { + } +}; + +var foo1: "foo" = b; + + +//// [stringLiteralValueInDestructuredConstDecl01.js] +var _a = { + a: {} +}.a.b, b = _a === void 0 ? "foo" : _a; +var foo1 = b; diff --git a/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl01.symbols b/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl01.symbols new file mode 100644 index 0000000000000..f1800706cd46b --- /dev/null +++ b/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl01.symbols @@ -0,0 +1,15 @@ +=== tests/cases/compiler/stringLiteralValueInDestructuredConstDecl01.ts === + +const {a: {b = "foo"}} = { +>a : Symbol(a, Decl(stringLiteralValueInDestructuredConstDecl01.ts, 1, 26)) +>b : Symbol(b, Decl(stringLiteralValueInDestructuredConstDecl01.ts, 1, 11)) + + a: { +>a : Symbol(a, Decl(stringLiteralValueInDestructuredConstDecl01.ts, 1, 26)) + } +}; + +var foo1: "foo" = b; +>foo1 : Symbol(foo1, Decl(stringLiteralValueInDestructuredConstDecl01.ts, 6, 3)) +>b : Symbol(b, Decl(stringLiteralValueInDestructuredConstDecl01.ts, 1, 11)) + diff --git a/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl01.types b/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl01.types new file mode 100644 index 0000000000000..b65a2f8ff8fd7 --- /dev/null +++ b/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl01.types @@ -0,0 +1,18 @@ +=== tests/cases/compiler/stringLiteralValueInDestructuredConstDecl01.ts === + +const {a: {b = "foo"}} = { +>a : any +>b : "foo" +>"foo" : "foo" +>{ a: { }} : { a: { b?: "foo"; }; } + + a: { +>a : { b?: "foo"; } +>{ } : { b?: "foo"; } + } +}; + +var foo1: "foo" = b; +>foo1 : "foo" +>b : "foo" + diff --git a/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl02.errors.txt b/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl02.errors.txt new file mode 100644 index 0000000000000..c1f00fa74e687 --- /dev/null +++ b/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl02.errors.txt @@ -0,0 +1,15 @@ +tests/cases/compiler/stringLiteralValueInDestructuredConstDecl02.ts(8,5): error TS2322: Type 'string' is not assignable to type '"foo"'. + + +==== tests/cases/compiler/stringLiteralValueInDestructuredConstDecl02.ts (1 errors) ==== + + const {x: {y}} = { + x: { + y: "foo" + } + }; + + var foo2: "foo" = y; + ~~~~ +!!! error TS2322: Type 'string' is not assignable to type '"foo"'. + \ No newline at end of file diff --git a/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl02.js b/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl02.js new file mode 100644 index 0000000000000..5690db21b2dc6 --- /dev/null +++ b/tests/baselines/reference/stringLiteralValueInDestructuredConstDecl02.js @@ -0,0 +1,18 @@ +//// [stringLiteralValueInDestructuredConstDecl02.ts] + +const {x: {y}} = { + x: { + y: "foo" + } +}; + +var foo2: "foo" = y; + + +//// [stringLiteralValueInDestructuredConstDecl02.js] +var y = { + x: { + y: "foo" + } +}.x.y; +var foo2 = y; diff --git a/tests/cases/compiler/stringLiteralValueInConstDecl01.ts b/tests/cases/compiler/stringLiteralValueInConstDecl01.ts new file mode 100644 index 0000000000000..4d99ac64acbc8 --- /dev/null +++ b/tests/cases/compiler/stringLiteralValueInConstDecl01.ts @@ -0,0 +1,5 @@ +// @noImplicitAny: true + +const foo = "foo"; +var bar = foo; +bar = "bar"; \ No newline at end of file diff --git a/tests/cases/compiler/stringLiteralValueInConstDecl02.ts b/tests/cases/compiler/stringLiteralValueInConstDecl02.ts new file mode 100644 index 0000000000000..8d74d251c9fae --- /dev/null +++ b/tests/cases/compiler/stringLiteralValueInConstDecl02.ts @@ -0,0 +1,20 @@ +// @noImplicitAny: true +// @module: es2015 + +const foo = "foo"; +const bar = "bar"; + +declare function randBool(): boolean; + +export function fooOrBar1() { + if (randBool()) { + return foo; + } + else { + return bar; + } +} + +export function fooOrBar2() { + return randBool() ? foo : bar; +} \ No newline at end of file diff --git a/tests/cases/compiler/stringLiteralValueInDestructuredConstDecl01.ts b/tests/cases/compiler/stringLiteralValueInDestructuredConstDecl01.ts new file mode 100644 index 0000000000000..022966356480f --- /dev/null +++ b/tests/cases/compiler/stringLiteralValueInDestructuredConstDecl01.ts @@ -0,0 +1,8 @@ +// @noImplicitAny: true + +const {a: {b = "foo"}} = { + a: { + } +}; + +var foo1: "foo" = b; diff --git a/tests/cases/compiler/stringLiteralValueInDestructuredConstDecl02.ts b/tests/cases/compiler/stringLiteralValueInDestructuredConstDecl02.ts new file mode 100644 index 0000000000000..31c02ec7e795f --- /dev/null +++ b/tests/cases/compiler/stringLiteralValueInDestructuredConstDecl02.ts @@ -0,0 +1,9 @@ +// @noImplicitAny: true + +const {x: {y}} = { + x: { + y: "foo" + } +}; + +var foo2: "foo" = y; diff --git a/tests/cases/fourslash/completionEntryForConst.ts b/tests/cases/fourslash/completionEntryForConst.ts index 42de1c20b523e..3e49648f3a3e9 100644 --- a/tests/cases/fourslash/completionEntryForConst.ts +++ b/tests/cases/fourslash/completionEntryForConst.ts @@ -4,4 +4,4 @@ /////**/ goTo.marker(); -verify.completionListContains("c", "const c: string", /*documentation*/ undefined, "const"); \ No newline at end of file +verify.completionListContains("c", 'const c: "s"', /*documentation*/ undefined, "const"); \ No newline at end of file