diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4555f247980df..76f6c139a9b66 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; @@ -7494,7 +7495,8 @@ namespace ts { if (signature.hasRestParameter) { const type = getTypeOfSymbol(last(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; @@ -8579,16 +8581,19 @@ namespace ts { // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution // for intersections of types with signatures can be deterministic. function getIntersectionType(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { - if (types.length === 0) { - return emptyObjectType; - } const typeSet: Type[] = []; const includes = addTypesToIntersection(typeSet, 0, types); if (includes & TypeFlags.Never) { return neverType; } - if (includes & TypeFlags.Any) { - return includes & TypeFlags.Wildcard ? wildcardType : anyType; + if (includes & TypeFlags.Wildcard) { + return wildcardType; + } + if (!strictAny && includes & TypeFlags.Any) { + return anyType; + } + if (!strictNullChecks && includes & TypeFlags.Nullable) { + return includes & TypeFlags.Undefined ? undefinedType : nullType; } if (includes & TypeFlags.String && includes & TypeFlags.StringLiteral || includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral || @@ -8598,6 +8603,9 @@ namespace ts { if (includes & TypeFlags.EmptyObject && !(includes & TypeFlags.Object)) { typeSet.push(emptyObjectType); } + if (typeSet.length === 0) { + return anyType; + } if (typeSet.length === 1) { return typeSet[0]; } @@ -10293,7 +10301,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. @@ -20023,7 +20031,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; @@ -23498,7 +23506,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 2f205f1e44e31..fdc8e26d9d094 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 350272db44a2b..41d66686723f8 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2032,7 +2032,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 f0bb5e5ed7d5d..b74d59578f4d0 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3567,6 +3567,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 a3cdb32df0702..e04caa1ef9b77 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4351,6 +4351,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 diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 3adc0f014b696..d0f46e74b443c 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2454,6 +2454,7 @@ declare namespace ts { sourceMap?: boolean; sourceRoot?: string; strict?: boolean; + strictAny?: boolean; strictFunctionTypes?: boolean; strictNullChecks?: boolean; strictPropertyInitialization?: boolean; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 70f2e0d0cdbf5..ddc50646c079d 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2454,6 +2454,7 @@ declare namespace ts { sourceMap?: boolean; sourceRoot?: string; strict?: boolean; + strictAny?: boolean; strictFunctionTypes?: boolean; strictNullChecks?: boolean; strictPropertyInitialization?: boolean; diff --git a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json index 0b72c3fd8a779..5f4091a44757e 100644 --- a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json @@ -23,6 +23,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictAny": true, /* Enable strict checking of 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with advanced options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with advanced options/tsconfig.json index 4d5c6053bcc76..094e73effa8f4 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with advanced options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with advanced options/tsconfig.json @@ -23,6 +23,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictAny": true, /* Enable strict checking of 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json index f84c7f3abf3f2..bcc52a15258c6 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json @@ -23,6 +23,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictAny": true, /* Enable strict checking of 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json index b65582c7841d2..e9356f7828b8a 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json @@ -23,6 +23,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictAny": true, /* Enable strict checking of 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json index 86d25e2362ac7..1fd4198988164 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json @@ -23,6 +23,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictAny": true, /* Enable strict checking of 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json index b623b1198c232..b1baf26d70db4 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json @@ -23,6 +23,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictAny": true, /* Enable strict checking of 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json index 0b72c3fd8a779..5f4091a44757e 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json @@ -23,6 +23,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictAny": true, /* Enable strict checking of 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json index ea9df560138df..cb6b2bf2409b1 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json @@ -23,6 +23,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictAny": true, /* Enable strict checking of 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json index bab4947a8e51b..d8e041a04ae01 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json @@ -23,6 +23,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictAny": true, /* Enable strict checking of 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/cases/compiler/APISample_jsdoc.ts b/tests/cases/compiler/APISample_jsdoc.ts index d40673f1d9ed0..0a824f9035750 100644 --- a/tests/cases/compiler/APISample_jsdoc.ts +++ b/tests/cases/compiler/APISample_jsdoc.ts @@ -2,6 +2,7 @@ // @skipLibCheck: true // @includebuiltfile: typescript_standalone.d.ts // @strict:true +// @strictAny:false /* * Note: This test is a public API sample. The original sources can be found diff --git a/tests/cases/compiler/contextualExpressionTypecheckingDoesntBlowStack.ts b/tests/cases/compiler/contextualExpressionTypecheckingDoesntBlowStack.ts index 9abff096a7631..12218d4db9e60 100644 --- a/tests/cases/compiler/contextualExpressionTypecheckingDoesntBlowStack.ts +++ b/tests/cases/compiler/contextualExpressionTypecheckingDoesntBlowStack.ts @@ -1,6 +1,7 @@ // @target: es5 // @lib: es6 // @strict: true +// @strictAny: false // repro for: https://github.com/Microsoft/TypeScript/issues/23661 export interface IValidationError { diff --git a/tests/cases/compiler/invariantGenericErrorElaboration.ts b/tests/cases/compiler/invariantGenericErrorElaboration.ts index 6191949dd8c7e..8bd4eae482fea 100644 --- a/tests/cases/compiler/invariantGenericErrorElaboration.ts +++ b/tests/cases/compiler/invariantGenericErrorElaboration.ts @@ -1,4 +1,5 @@ // @strict: true +// @strictAny: false // Repro from #19746 diff --git a/tests/cases/conformance/types/conditional/conditionalTypes2.ts b/tests/cases/conformance/types/conditional/conditionalTypes2.ts index be75894546944..8b8d2be57e4a5 100644 --- a/tests/cases/conformance/types/conditional/conditionalTypes2.ts +++ b/tests/cases/conformance/types/conditional/conditionalTypes2.ts @@ -1,4 +1,5 @@ // @strict: true +// @strictAny: false // @declaration: true interface Covariant { diff --git a/tests/cases/conformance/types/conditional/inferTypes1.ts b/tests/cases/conformance/types/conditional/inferTypes1.ts index 6f31b8e49eb9c..863a4ca5ee804 100644 --- a/tests/cases/conformance/types/conditional/inferTypes1.ts +++ b/tests/cases/conformance/types/conditional/inferTypes1.ts @@ -1,4 +1,5 @@ // @strict: true +// @strictAny: false // @declaration: true type Unpacked = diff --git a/tests/cases/conformance/types/mapped/mappedTypeWithAny.ts b/tests/cases/conformance/types/mapped/mappedTypeWithAny.ts index f8b6f8a39b7d2..17081e0b8e5c4 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeWithAny.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeWithAny.ts @@ -1,4 +1,5 @@ // @strict: true +// @strictAny: false // @declaration: true type Item = { value: string }; diff --git a/tests/cases/conformance/types/mapped/mappedTypes5.ts b/tests/cases/conformance/types/mapped/mappedTypes5.ts index 38a010da0f549..a681e951388e9 100644 --- a/tests/cases/conformance/types/mapped/mappedTypes5.ts +++ b/tests/cases/conformance/types/mapped/mappedTypes5.ts @@ -1,4 +1,5 @@ // @strict: true +// @strictAny: false function f(p: Partial, r: Readonly, pr: Partial>, rp: Readonly>) { let a1: Partial = p;