Skip to content

Infer string literals types in const declarations #5796

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
7 changes: 7 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
34 changes: 32 additions & 2 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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) ?
Expand All @@ -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)) {
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/constDeclarations-es5.types
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const z9 = 0, z10 :string = "", z11 = null;
>z9 : number
>0 : number
>z10 : string
>"" : string
>"" : ""
>z11 : any
>null : null

4 changes: 2 additions & 2 deletions tests/baselines/reference/constDeclarations-scopes2.types
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

// global
const c = "string";
>c : string
>"string" : string
>c : "string"
>"string" : "string"

var n: number;
>n : number
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/constDeclarations.types
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const c3 = 0, c4 :string = "", c5 = null;
>c3 : number
>0 : number
>c4 : string
>"" : string
>"" : ""
>c5 : any
>null : null

Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/constDeclarations2.types
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module M {
>c3 : number
>0 : number
>c4 : string
>"" : string
>"" : ""
>c5 : any
>null : null
}
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/downlevelLetConst13.types
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/downlevelLetConst15.types
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ var y = true;
>true : boolean
{
const y = "";
>y : string
>"" : string
>y : ""
>"" : ""

const [z6] = [true]
>z6 : boolean
Expand Down Expand Up @@ -140,7 +140,7 @@ var y = true;
use(y);
>use(y) : any
>use : (a: any) => any
>y : string
>y : ""

use(z6);
>use(z6) : any
Expand All @@ -166,8 +166,8 @@ var z5 = 1;
>1 : number
{
const z = "";
>z : string
>"" : string
>z : ""
>"" : ""

const [z5] = [5];
>z5 : number
Expand All @@ -194,7 +194,7 @@ var z5 = 1;
use(z);
>use(z) : any
>use : (a: any) => any
>z : string
>z : ""
}
use(y);
>use(y) : any
Expand Down
46 changes: 23 additions & 23 deletions tests/baselines/reference/es6ModuleConst.types
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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"
}
Original file line number Diff line number Diff line change
@@ -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"'.
10 changes: 10 additions & 0 deletions tests/baselines/reference/stringLiteralValueInConstDecl01.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//// [stringLiteralValueInConstDecl01.ts]

const foo = "foo";
var bar = foo;
bar = "bar";

//// [stringLiteralValueInConstDecl01.js]
var foo = "foo";
var bar = foo;
bar = "bar";
Original file line number Diff line number Diff line change
@@ -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;
}
34 changes: 34 additions & 0 deletions tests/baselines/reference/stringLiteralValueInConstDecl02.js
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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))

Original file line number Diff line number Diff line change
@@ -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"

Original file line number Diff line number Diff line change
@@ -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"'.

Loading