diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cb9912c47d0..9cff537b07f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5547,7 +5547,7 @@ module ts { } // Fall back to any. - if (compilerOptions.noImplicitAny && objectType !== anyType) { + if (compilerOptions.noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && objectType !== anyType) { error(node, Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type); } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 3fabf6c8588..ae4c751869c 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -88,6 +88,11 @@ module ts { description: Diagnostics.Redirect_output_structure_to_the_directory, paramType: Diagnostics.DIRECTORY, }, + { + name: "preserveConstEnums", + type: "boolean", + description: Diagnostics.Do_not_erase_const_enum_declarations_in_generated_code + }, { name: "removeComments", type: "boolean", @@ -104,6 +109,11 @@ module ts { description: Diagnostics.Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations, paramType: Diagnostics.LOCATION, }, + { + name: "suppressImplicitAnyIndexErrors", + type: "boolean", + description: Diagnostics.Suppress_noImplicitAny_errors_for_indexing_objects_lacking_index_signatures, + }, { name: "target", shortName: "t", @@ -124,13 +134,8 @@ module ts { type: "boolean", description: Diagnostics.Watch_input_files, }, - { - name: "preserveConstEnums", - type: "boolean", - description: Diagnostics.Do_not_erase_const_enum_declarations_in_generated_code - } ]; - + var shortOptionNames: Map = {}; var optionNameMap: Map = {}; diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 17dbae83bf2..e565734f64c 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -416,6 +416,7 @@ module ts { Warn_on_expressions_and_declarations_with_an_implied_any_type: { code: 6052, category: DiagnosticCategory.Message, key: "Warn on expressions and declarations with an implied 'any' type." }, File_0_not_found: { code: 6053, category: DiagnosticCategory.Error, key: "File '{0}' not found." }, File_0_must_have_extension_ts_or_d_ts: { code: 6054, category: DiagnosticCategory.Error, key: "File '{0}' must have extension '.ts' or '.d.ts'." }, + Suppress_noImplicitAny_errors_for_indexing_objects_lacking_index_signatures: { code: 6055, category: DiagnosticCategory.Message, key: "Suppress noImplicitAny errors for indexing objects lacking index signatures." }, Variable_0_implicitly_has_an_1_type: { code: 7005, category: DiagnosticCategory.Error, key: "Variable '{0}' implicitly has an '{1}' type." }, Parameter_0_implicitly_has_an_1_type: { code: 7006, category: DiagnosticCategory.Error, key: "Parameter '{0}' implicitly has an '{1}' type." }, Member_0_implicitly_has_an_1_type: { code: 7008, category: DiagnosticCategory.Error, key: "Member '{0}' implicitly has an '{1}' type." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a06b71d460e..9285b4c509d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1663,6 +1663,10 @@ "category": "Error", "code": 6054 }, + "Suppress noImplicitAny errors for indexing objects lacking index signatures.": { + "category": "Message", + "code": 6055 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c632c68c34f..ee63b0f380f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -9,9 +9,9 @@ module ts { export function getNodeConstructor(kind: SyntaxKind): new () => Node { return nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind)); } - + export function createNode(kind: SyntaxKind): Node { - return new (getNodeConstructor(kind))(); + return new (getNodeConstructor(kind))(); } // Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes @@ -286,11 +286,11 @@ module ts { } text = ""; } + return text !== undefined ? createSourceFile(filename, text, languageVersion) : undefined; } - function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) { - + function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) { function directoryExists(directoryPath: string): boolean { if (hasProperty(existingDirectories, directoryPath)) { return true; @@ -400,7 +400,7 @@ module ts { } return 0; } - + function fixupParentReferences(sourceFile: SourceFile) { // normally parent references are set during binding. // however here SourceFile data is used only for syntactic features so running the whole binding process is an overhead. @@ -422,7 +422,7 @@ module ts { forEachChild(sourceFile, walk); } - + function isEvalOrArgumentsIdentifier(node: Node): boolean { return node.kind === SyntaxKind.Identifier && ((node).text === "eval" || (node).text === "arguments"); @@ -434,8 +434,8 @@ module ts { var nodeText = getSourceTextOfNodeFromSourceFile(sourceFile,(node).expression); return nodeText === '"use strict"' || nodeText === "'use strict'"; } - - export function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false): SourceFile { + + export function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false): SourceFile { var parsingContext: ParsingContext; var identifiers: Map = {}; var identifierCount = 0; diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 5e4918d91e9..bc4d48b7513 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -378,12 +378,12 @@ module ts { var usageText = " "; if (option.shortName) { usageText += "-" + option.shortName; - usageText += getParamName(option); + usageText += getParamType(option); usageText += ", "; } usageText += "--" + option.name; - usageText += getParamName(option); + usageText += getParamType(option); usageColumn.push(usageText); descriptionColumn.push(getDiagnosticText(option.description)); @@ -408,9 +408,9 @@ module ts { sys.write(output); return; - function getParamName(option: CommandLineOption) { - if (option.paramName !== undefined) { - return " " + getDiagnosticText(option.paramName); + function getParamType(option: CommandLineOption) { + if (option.paramType !== undefined) { + return " " + getDiagnosticText(option.paramType); } return ""; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 96e644f8e1a..ac5dff627d5 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1395,6 +1395,7 @@ module ts { } export interface CompilerOptions { + allowNonTsExtensions?: boolean; charset?: string; codepage?: number; declaration?: boolean; @@ -1412,14 +1413,14 @@ module ts { noResolve?: boolean; out?: string; outDir?: string; + preserveConstEnums?: boolean; removeComments?: boolean; sourceMap?: boolean; sourceRoot?: string; + suppressImplicitAnyIndexErrors?: boolean; target?: ScriptTarget; version?: boolean; watch?: boolean; - preserveConstEnums?: boolean; - allowNonTsExtensions?: boolean; [option: string]: string | number | boolean; } @@ -1456,7 +1457,7 @@ module ts { type: string | Map; // "string", "number", "boolean", or an object literal mapping named values to actual values shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help'. description?: DiagnosticMessage; // The message describing what the command line switch does - paramName?: DiagnosticMessage; // The name to be used for a non-boolean option's parameter. + paramType?: DiagnosticMessage; // The name to be used for a non-boolean option's parameter. error?: DiagnosticMessage; // The error given when the argument does not fit a customized 'type'. } @@ -1594,7 +1595,7 @@ module ts { tab = 0x09, // \t verticalTab = 0x0B, // \v } - + export interface CancellationToken { isCancellationRequested(): boolean; } diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 9bab6596fe6..5a4837949a5 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -842,6 +842,10 @@ module Harness { options.preserveConstEnums = setting.value === 'true'; break; + case 'suppressimplicitanyindexerrors': + options.suppressImplicitAnyIndexErrors = setting.value === 'true'; + break; + case 'includebuiltfile': inputFiles.push({ unitName: setting.value, content: IO.readFile(libFolder + setting.value)}); break; @@ -1235,7 +1239,7 @@ module Harness { var optionRegex = /^[\/]{2}\s*@(\w+)\s*:\s*(\S*)/gm; // multiple matches on multiple lines // List of allowed metadata names - var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noemitonerror", "noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames", "preserveconstenums", "includebuiltfile"]; + var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noemitonerror", "noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames", "preserveconstenums", "includebuiltfile", "suppressimplicitanyindexerrors"]; function extractCompilerSettings(content: string): CompilerSetting[] { diff --git a/tests/baselines/reference/APISample_node_compile.js b/tests/baselines/reference/APISample_node_compile.js index 223ba05429d..a102edcb6f6 100644 --- a/tests/baselines/reference/APISample_node_compile.js +++ b/tests/baselines/reference/APISample_node_compile.js @@ -1114,6 +1114,7 @@ declare module "typescript" { Message = 2, } interface CompilerOptions { + allowNonTsExtensions?: boolean; charset?: string; codepage?: number; declaration?: boolean; @@ -1131,14 +1132,14 @@ declare module "typescript" { noResolve?: boolean; out?: string; outDir?: string; + preserveConstEnums?: boolean; removeComments?: boolean; sourceMap?: boolean; sourceRoot?: string; + suppressImplicitAnyIndexErrors?: boolean; target?: ScriptTarget; version?: boolean; watch?: boolean; - preserveConstEnums?: boolean; - allowNonTsExtensions?: boolean; [option: string]: string | number | boolean; } const enum ModuleKind { @@ -1166,7 +1167,7 @@ declare module "typescript" { type: string | Map; shortName?: string; description?: DiagnosticMessage; - paramName?: DiagnosticMessage; + paramType?: DiagnosticMessage; error?: DiagnosticMessage; } const enum CharacterCodes { diff --git a/tests/baselines/reference/APISample_node_compile.types b/tests/baselines/reference/APISample_node_compile.types index fa881875212..d37801c7088 100644 --- a/tests/baselines/reference/APISample_node_compile.types +++ b/tests/baselines/reference/APISample_node_compile.types @@ -3551,6 +3551,9 @@ declare module "typescript" { interface CompilerOptions { >CompilerOptions : CompilerOptions + allowNonTsExtensions?: boolean; +>allowNonTsExtensions : boolean + charset?: string; >charset : string @@ -3603,6 +3606,9 @@ declare module "typescript" { outDir?: string; >outDir : string + preserveConstEnums?: boolean; +>preserveConstEnums : boolean + removeComments?: boolean; >removeComments : boolean @@ -3612,6 +3618,9 @@ declare module "typescript" { sourceRoot?: string; >sourceRoot : string + suppressImplicitAnyIndexErrors?: boolean; +>suppressImplicitAnyIndexErrors : boolean + target?: ScriptTarget; >target : ScriptTarget >ScriptTarget : ScriptTarget @@ -3622,12 +3631,6 @@ declare module "typescript" { watch?: boolean; >watch : boolean - preserveConstEnums?: boolean; ->preserveConstEnums : boolean - - allowNonTsExtensions?: boolean; ->allowNonTsExtensions : boolean - [option: string]: string | number | boolean; >option : string } @@ -3698,8 +3701,8 @@ declare module "typescript" { >description : DiagnosticMessage >DiagnosticMessage : DiagnosticMessage - paramName?: DiagnosticMessage; ->paramName : DiagnosticMessage + paramType?: DiagnosticMessage; +>paramType : DiagnosticMessage >DiagnosticMessage : DiagnosticMessage error?: DiagnosticMessage; diff --git a/tests/baselines/reference/APISample_standalone_compile.js b/tests/baselines/reference/APISample_standalone_compile.js index c885aa03c54..2917c605c7d 100644 --- a/tests/baselines/reference/APISample_standalone_compile.js +++ b/tests/baselines/reference/APISample_standalone_compile.js @@ -1112,6 +1112,7 @@ declare module ts { Message = 2, } interface CompilerOptions { + allowNonTsExtensions?: boolean; charset?: string; codepage?: number; declaration?: boolean; @@ -1129,14 +1130,14 @@ declare module ts { noResolve?: boolean; out?: string; outDir?: string; + preserveConstEnums?: boolean; removeComments?: boolean; sourceMap?: boolean; sourceRoot?: string; + suppressImplicitAnyIndexErrors?: boolean; target?: ScriptTarget; version?: boolean; watch?: boolean; - preserveConstEnums?: boolean; - allowNonTsExtensions?: boolean; [option: string]: string | number | boolean; } const enum ModuleKind { @@ -1164,7 +1165,7 @@ declare module ts { type: string | Map; shortName?: string; description?: DiagnosticMessage; - paramName?: DiagnosticMessage; + paramType?: DiagnosticMessage; error?: DiagnosticMessage; } const enum CharacterCodes { diff --git a/tests/baselines/reference/APISample_standalone_compile.types b/tests/baselines/reference/APISample_standalone_compile.types index 804aa67e64e..03ce45a07cc 100644 --- a/tests/baselines/reference/APISample_standalone_compile.types +++ b/tests/baselines/reference/APISample_standalone_compile.types @@ -3550,6 +3550,9 @@ declare module ts { interface CompilerOptions { >CompilerOptions : CompilerOptions + allowNonTsExtensions?: boolean; +>allowNonTsExtensions : boolean + charset?: string; >charset : string @@ -3602,6 +3605,9 @@ declare module ts { outDir?: string; >outDir : string + preserveConstEnums?: boolean; +>preserveConstEnums : boolean + removeComments?: boolean; >removeComments : boolean @@ -3611,6 +3617,9 @@ declare module ts { sourceRoot?: string; >sourceRoot : string + suppressImplicitAnyIndexErrors?: boolean; +>suppressImplicitAnyIndexErrors : boolean + target?: ScriptTarget; >target : ScriptTarget >ScriptTarget : ScriptTarget @@ -3621,12 +3630,6 @@ declare module ts { watch?: boolean; >watch : boolean - preserveConstEnums?: boolean; ->preserveConstEnums : boolean - - allowNonTsExtensions?: boolean; ->allowNonTsExtensions : boolean - [option: string]: string | number | boolean; >option : string } @@ -3697,8 +3700,8 @@ declare module ts { >description : DiagnosticMessage >DiagnosticMessage : DiagnosticMessage - paramName?: DiagnosticMessage; ->paramName : DiagnosticMessage + paramType?: DiagnosticMessage; +>paramType : DiagnosticMessage >DiagnosticMessage : DiagnosticMessage error?: DiagnosticMessage; diff --git a/tests/baselines/reference/noImplicitAnyIndexingSuppressed.js b/tests/baselines/reference/noImplicitAnyIndexingSuppressed.js new file mode 100644 index 00000000000..5185a9b8db8 --- /dev/null +++ b/tests/baselines/reference/noImplicitAnyIndexingSuppressed.js @@ -0,0 +1,81 @@ +//// [noImplicitAnyIndexingSuppressed.ts] + +enum MyEmusEnum { + emu +} + +// Should be okay; should be a string. +var strRepresentation1 = MyEmusEnum[0] + +// Should be okay; should be a string. +var strRepresentation2 = MyEmusEnum[MyEmusEnum.emu] + +// Should be okay, as we suppress implicit 'any' property access checks +var strRepresentation3 = MyEmusEnum["monehh"]; + +// Should be okay; should be a MyEmusEnum +var strRepresentation4 = MyEmusEnum["emu"]; + + +// Should be okay, as we suppress implicit 'any' property access checks +var x = {}["hi"]; + +// Should be okay, as we suppress implicit 'any' property access checks +var y = {}[10]; + +var hi: any = "hi"; + +var emptyObj = {}; + +// Should be okay, as we suppress implicit 'any' property access checks +var z1 = emptyObj[hi]; +var z2 = (emptyObj)[hi]; + +interface MyMap { + [key: string]: T; +} + +var m: MyMap = { + "0": 0, + "1": 1, + "2": 2, + "Okay that's enough for today.": NaN +}; + +var mResult1 = m[MyEmusEnum.emu]; +var mResult2 = m[MyEmusEnum[MyEmusEnum.emu]]; +var mResult3 = m[hi]; + + + +//// [noImplicitAnyIndexingSuppressed.js] +var MyEmusEnum; +(function (MyEmusEnum) { + MyEmusEnum[MyEmusEnum["emu"] = 0] = "emu"; +})(MyEmusEnum || (MyEmusEnum = {})); +// Should be okay; should be a string. +var strRepresentation1 = MyEmusEnum[0]; +// Should be okay; should be a string. +var strRepresentation2 = MyEmusEnum[0 /* emu */]; +// Should be okay, as we suppress implicit 'any' property access checks +var strRepresentation3 = MyEmusEnum["monehh"]; +// Should be okay; should be a MyEmusEnum +var strRepresentation4 = 0 /* "emu" */; +// Should be okay, as we suppress implicit 'any' property access checks +var x = {}["hi"]; +// Should be okay, as we suppress implicit 'any' property access checks +var y = {}[10]; +var hi = "hi"; +var emptyObj = {}; +// Should be okay, as we suppress implicit 'any' property access checks +var z1 = emptyObj[hi]; +var z2 = emptyObj[hi]; +var m = { + "0": 0, + "1": 1, + "2": 2, + "Okay that's enough for today.": NaN +}; +var mResult1 = m[0 /* emu */]; +var mResult2 = m[MyEmusEnum[0 /* emu */]]; +var mResult3 = m[hi]; diff --git a/tests/baselines/reference/noImplicitAnyIndexingSuppressed.types b/tests/baselines/reference/noImplicitAnyIndexingSuppressed.types new file mode 100644 index 00000000000..20be75dc29e --- /dev/null +++ b/tests/baselines/reference/noImplicitAnyIndexingSuppressed.types @@ -0,0 +1,118 @@ +=== tests/cases/compiler/noImplicitAnyIndexingSuppressed.ts === + +enum MyEmusEnum { +>MyEmusEnum : MyEmusEnum + + emu +>emu : MyEmusEnum +} + +// Should be okay; should be a string. +var strRepresentation1 = MyEmusEnum[0] +>strRepresentation1 : string +>MyEmusEnum[0] : string +>MyEmusEnum : typeof MyEmusEnum + +// Should be okay; should be a string. +var strRepresentation2 = MyEmusEnum[MyEmusEnum.emu] +>strRepresentation2 : string +>MyEmusEnum[MyEmusEnum.emu] : string +>MyEmusEnum : typeof MyEmusEnum +>MyEmusEnum.emu : MyEmusEnum +>MyEmusEnum : typeof MyEmusEnum +>emu : MyEmusEnum + +// Should be okay, as we suppress implicit 'any' property access checks +var strRepresentation3 = MyEmusEnum["monehh"]; +>strRepresentation3 : any +>MyEmusEnum["monehh"] : any +>MyEmusEnum : typeof MyEmusEnum + +// Should be okay; should be a MyEmusEnum +var strRepresentation4 = MyEmusEnum["emu"]; +>strRepresentation4 : MyEmusEnum +>MyEmusEnum["emu"] : MyEmusEnum +>MyEmusEnum : typeof MyEmusEnum + + +// Should be okay, as we suppress implicit 'any' property access checks +var x = {}["hi"]; +>x : any +>{}["hi"] : any +>{} : {} + +// Should be okay, as we suppress implicit 'any' property access checks +var y = {}[10]; +>y : any +>{}[10] : any +>{} : {} + +var hi: any = "hi"; +>hi : any + +var emptyObj = {}; +>emptyObj : {} +>{} : {} + +// Should be okay, as we suppress implicit 'any' property access checks +var z1 = emptyObj[hi]; +>z1 : any +>emptyObj[hi] : any +>emptyObj : {} +>hi : any + +var z2 = (emptyObj)[hi]; +>z2 : any +>(emptyObj)[hi] : any +>(emptyObj) : any +>emptyObj : any +>emptyObj : {} +>hi : any + +interface MyMap { +>MyMap : MyMap +>T : T + + [key: string]: T; +>key : string +>T : T +} + +var m: MyMap = { +>m : MyMap +>MyMap : MyMap +>{ "0": 0, "1": 1, "2": 2, "Okay that's enough for today.": NaN} : { [x: string]: number; "0": number; "1": number; "2": number; "Okay that's enough for today.": number; } + + "0": 0, + "1": 1, + "2": 2, + "Okay that's enough for today.": NaN +>NaN : number + +}; + +var mResult1 = m[MyEmusEnum.emu]; +>mResult1 : number +>m[MyEmusEnum.emu] : number +>m : MyMap +>MyEmusEnum.emu : MyEmusEnum +>MyEmusEnum : typeof MyEmusEnum +>emu : MyEmusEnum + +var mResult2 = m[MyEmusEnum[MyEmusEnum.emu]]; +>mResult2 : number +>m[MyEmusEnum[MyEmusEnum.emu]] : number +>m : MyMap +>MyEmusEnum[MyEmusEnum.emu] : string +>MyEmusEnum : typeof MyEmusEnum +>MyEmusEnum.emu : MyEmusEnum +>MyEmusEnum : typeof MyEmusEnum +>emu : MyEmusEnum + +var mResult3 = m[hi]; +>mResult3 : number +>m[hi] : number +>m : MyMap +>hi : any + + diff --git a/tests/cases/compiler/noImplicitAnyIndexingSuppressed.ts b/tests/cases/compiler/noImplicitAnyIndexingSuppressed.ts new file mode 100644 index 00000000000..42ae529fddc --- /dev/null +++ b/tests/cases/compiler/noImplicitAnyIndexingSuppressed.ts @@ -0,0 +1,49 @@ +//@noImplicitAny: true +//@suppressImplicitAnyIndexErrors: true + +enum MyEmusEnum { + emu +} + +// Should be okay; should be a string. +var strRepresentation1 = MyEmusEnum[0] + +// Should be okay; should be a string. +var strRepresentation2 = MyEmusEnum[MyEmusEnum.emu] + +// Should be okay, as we suppress implicit 'any' property access checks +var strRepresentation3 = MyEmusEnum["monehh"]; + +// Should be okay; should be a MyEmusEnum +var strRepresentation4 = MyEmusEnum["emu"]; + + +// Should be okay, as we suppress implicit 'any' property access checks +var x = {}["hi"]; + +// Should be okay, as we suppress implicit 'any' property access checks +var y = {}[10]; + +var hi: any = "hi"; + +var emptyObj = {}; + +// Should be okay, as we suppress implicit 'any' property access checks +var z1 = emptyObj[hi]; +var z2 = (emptyObj)[hi]; + +interface MyMap { + [key: string]: T; +} + +var m: MyMap = { + "0": 0, + "1": 1, + "2": 2, + "Okay that's enough for today.": NaN +}; + +var mResult1 = m[MyEmusEnum.emu]; +var mResult2 = m[MyEmusEnum[MyEmusEnum.emu]]; +var mResult3 = m[hi]; +