String and numeric literal initializes in ambient const declarations

This commit is contained in:
Anders Hejlsberg 2016-09-26 12:46:39 -07:00
parent a8e004255e
commit e1d5bdffd7
4 changed files with 51 additions and 6 deletions

View File

@ -2015,6 +2015,10 @@ namespace ts {
isExternalModuleAugmentation(node.parent.parent);
}
function literalTypeToString(type: LiteralType) {
return type.flags & TypeFlags.StringLiteral ? `"${escapeString((<LiteralType>type).text)}"` : (<LiteralType>type).text;
}
function getSymbolDisplayBuilder(): SymbolDisplayBuilder {
function getNameOfSymbol(symbol: Symbol): string {
@ -2190,11 +2194,8 @@ namespace ts {
else if (type.flags & TypeFlags.Anonymous) {
writeAnonymousType(<ObjectType>type, nextFlags);
}
else if (type.flags & TypeFlags.StringLiteral) {
writer.writeStringLiteral(`"${escapeString((<LiteralType>type).text)}"`);
}
else if (type.flags & TypeFlags.NumberLiteral) {
writer.writeStringLiteral((<LiteralType>type).text);
else if (type.flags & TypeFlags.StringOrNumberLiteral) {
writer.writeStringLiteral(literalTypeToString(<LiteralType>type));
}
else {
// Should never get here
@ -19015,6 +19016,19 @@ namespace ts {
return undefined;
}
function isLiteralConstDeclaration(node: VariableDeclaration): boolean {
if (isConst(node)) {
const type = getTypeOfSymbol(getSymbolOfNode(node));
return !!(type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral);
}
return false;
}
function writeLiteralConstValue(node: VariableDeclaration, writer: SymbolWriter) {
const type = getTypeOfSymbol(getSymbolOfNode(node));
writer.writeStringLiteral(literalTypeToString(<LiteralType>type));
}
function createResolver(): EmitResolver {
// this variable and functions that use it are deliberately moved here from the outer scope
// to avoid scope pollution
@ -19059,7 +19073,9 @@ namespace ts {
isArgumentsLocalBinding,
getExternalModuleFileFromDeclaration,
getTypeReferenceDirectivesForEntityName,
getTypeReferenceDirectivesForSymbol
getTypeReferenceDirectivesForSymbol,
isLiteralConstDeclaration,
writeLiteralConstValue
};
// defined here to avoid outer scope pollution
@ -20205,10 +20221,29 @@ namespace ts {
}
}
function isStringOrNumberLiteralExpression(expr: Expression) {
return expr.kind === SyntaxKind.StringLiteral || expr.kind === SyntaxKind.NumericLiteral ||
expr.kind === SyntaxKind.PrefixUnaryExpression && (<PrefixUnaryExpression>expr).operator === SyntaxKind.MinusToken &&
(<PrefixUnaryExpression>expr).operand.kind === SyntaxKind.NumericLiteral;
}
function checkGrammarVariableDeclaration(node: VariableDeclaration) {
if (node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) {
if (isInAmbientContext(node)) {
if (node.initializer) {
if (isConst(node) && !node.type) {
if (!isStringOrNumberLiteralExpression(node.initializer)) {
return grammarErrorOnNode(node.initializer, Diagnostics.A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal);
}
}
else {
// Error on equals token which immediate precedes the initializer
const equalsTokenLength = "=".length;
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - equalsTokenLength,
equalsTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
}
}
if (node.initializer && !(isConst(node) && isStringOrNumberLiteralExpression(node.initializer))) {
// Error on equals token which immediate precedes the initializer
const equalsTokenLength = "=".length;
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - equalsTokenLength,

View File

@ -1142,6 +1142,10 @@ namespace ts {
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) {
emitTypeOfVariableDeclarationFromTypeLiteral(node);
}
else if (resolver.isLiteralConstDeclaration(node)) {
write(" = ");
resolver.writeLiteralConstValue(node, writer);
}
else if (!hasModifier(node, ModifierFlags.Private)) {
writeTypeOfDeclaration(node, node.type, getVariableDeclarationTypeVisibilityError);
}

View File

@ -819,6 +819,10 @@
"category": "Error",
"code": 1253
},
"A 'const' initializer in an ambient context must be a string or numeric literal.": {
"category": "Error",
"code": 1254
},
"'with' statements are not allowed in an async function block.": {
"category": "Error",
"code": 1300

View File

@ -2156,6 +2156,8 @@ namespace ts {
getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): SourceFile;
getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): string[];
getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[];
isLiteralConstDeclaration(node: VariableDeclaration): boolean;
writeLiteralConstValue(node: VariableDeclaration, writer: SymbolWriter): void;
}
export const enum SymbolFlags {