diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8f7a54089bc..67e85aed170 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -65,6 +65,7 @@ namespace ts { const strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks"); const strictFunctionTypes = getStrictOptionValue(compilerOptions, "strictFunctionTypes"); const strictPropertyInitialization = getStrictOptionValue(compilerOptions, "strictPropertyInitialization"); + const strictAny = getStrictOptionValue(compilerOptions, "strictAny"); const noImplicitAny = getStrictOptionValue(compilerOptions, "noImplicitAny"); const noImplicitThis = getStrictOptionValue(compilerOptions, "noImplicitThis"); const keyofStringsOnly = !!compilerOptions.keyofStringsOnly; @@ -7464,7 +7465,8 @@ namespace ts { if (signature.hasRestParameter) { const type = getTypeOfSymbol(lastOrUndefined(signature.parameters)); if (getObjectFlags(type) & ObjectFlags.Reference && (type).target === globalArrayType) { - return (type).typeArguments[0]; + const t = (type).typeArguments[0]; + return strictAny && t.flags & TypeFlags.Any ? unknownType : t; } } return anyType; @@ -10248,7 +10250,7 @@ namespace ts { if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive) return true; if (s & TypeFlags.UniqueESSymbol || t & TypeFlags.UniqueESSymbol) return false; if (relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) { - if (s & TypeFlags.Any) return true; + if (s & TypeFlags.Any && (!strictAny || source === unknownType || t & TypeFlags.Object && isEmptyObjectType(target))) return true; // Type number or any numeric literal type is assignable to any numeric enum type or any // numeric enum literal type. This rule exists for backwards compatibility reasons because // bit-flag enum types sometimes look like literal enum types with numeric literal values. @@ -19935,7 +19937,7 @@ namespace ts { if (!(isTypeComparableTo(leftType, stringType) || isTypeAssignableToKind(leftType, TypeFlags.NumberLike | TypeFlags.ESSymbolLike))) { error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol); } - if (!isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive)) { + if (!(rightType.flags & TypeFlags.Any || isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive))) { error(right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); } return booleanType; @@ -23410,7 +23412,7 @@ namespace ts { // unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved // in this case error about missing name is already reported - do not report extra one - if (rightType === neverType || !isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive)) { + if (rightType === neverType || !(rightType.flags & TypeFlags.Any || isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive))) { error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter_but_here_has_type_0, typeToString(rightType)); } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 8b963409ab6..cf55d3414d0 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -290,6 +290,13 @@ namespace ts { category: Diagnostics.Strict_Type_Checking_Options, description: Diagnostics.Raise_error_on_expressions_and_declarations_with_an_implied_any_type, }, + { + name: "strictAny", + type: "boolean", + showInSimplifiedHelpView: true, + category: Diagnostics.Strict_Type_Checking_Options, + description: Diagnostics.Enable_strict_checking_of_any_type + }, { name: "strictNullChecks", type: "boolean", diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 4dd0fd0358a..e809b99630a 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2008,7 +2008,7 @@ namespace ts { return !!(compilerOptions.declaration || compilerOptions.composite); } - export type StrictOptionName = "noImplicitAny" | "noImplicitThis" | "strictNullChecks" | "strictFunctionTypes" | "strictPropertyInitialization" | "alwaysStrict"; + export type StrictOptionName = "noImplicitAny" | "noImplicitThis" | "strictNullChecks" | "strictFunctionTypes" | "strictPropertyInitialization" | "alwaysStrict" | "strictAny"; export function getStrictOptionValue(compilerOptions: CompilerOptions, flag: StrictOptionName): boolean { return compilerOptions[flag] === undefined ? compilerOptions.strict : compilerOptions[flag]; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 761e89ae645..1a997e118f9 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3561,6 +3561,10 @@ "code": 6199, "reportsUnnecessary": true }, + "Enable strict checking of 'any' type.": { + "category": "Message", + "code": 6200 + }, "Projects to reference": { "category": "Message", diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 19e526ba056..6875c06f604 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4341,6 +4341,7 @@ namespace ts { sourceMap?: boolean; sourceRoot?: string; strict?: boolean; + strictAny?: boolean; // Always combine with strict property strictFunctionTypes?: boolean; // Always combine with strict property strictNullChecks?: boolean; // Always combine with strict property strictPropertyInitialization?: boolean; // Always combine with strict property