diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ab8e3655541..a4f690137d5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3132,45 +3132,6 @@ module ts { return (type.flags & TypeFlags.Anonymous) && type.symbol && (type.symbol.flags & SymbolFlags.ObjectLiteral) ? true : false; } - function getWidenedTypeOfObjectLiteral(type: Type): Type { - var properties = getPropertiesOfType(type); - if (properties.length) { - var widenedTypes: Type[] = []; - var propTypeWasWidened: boolean = false; - forEach(properties, p => { - var propType = getTypeOfSymbol(p); - var widenedType = getWidenedType(propType); - if (propType !== widenedType) { - propTypeWasWidened = true; - - if (program.getCompilerOptions().noImplicitAny && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { - error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(widenedType)); - } - } - widenedTypes.push(widenedType); - }); - if (propTypeWasWidened) { - var members: SymbolTable = {}; - var index = 0; - forEach(properties, p => { - var symbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, p.name); - symbol.declarations = p.declarations; - symbol.parent = p.parent; - symbol.type = widenedTypes[index++]; - symbol.target = p; - if (p.valueDeclaration) symbol.valueDeclaration = p.valueDeclaration; - members[symbol.name] = symbol; - }); - var stringIndexType = getIndexTypeOfType(type, IndexKind.String); - var numberIndexType = getIndexTypeOfType(type, IndexKind.Number); - if (stringIndexType) stringIndexType = getWidenedType(stringIndexType); - if (numberIndexType) numberIndexType = getWidenedType(numberIndexType); - type = createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexType, numberIndexType); - } - } - return type; - } - function isArrayType(type: Type): boolean { return type.flags & TypeFlags.Reference && (type).target === globalArrayType; } @@ -3183,17 +3144,8 @@ module ts { return type; } - function getWidenedTypeOfArrayLiteral(type: Type): Type { - var elementType = (type).typeArguments[0]; - var widenedType = getWidenedType(elementType); - - type = elementType !== widenedType ? createArrayType(widenedType) : type; - - return type; - } - /* If we are widening on a literal, then we may need to the 'node' parameter for reporting purposes */ - function getWidenedType(type: Type): Type { + function getWidenedType(type: Type, supressNoImplicitAnyErrors?: boolean): Type { if (type.flags & (TypeFlags.Undefined | TypeFlags.Null)) { return anyType; } @@ -3204,6 +3156,54 @@ module ts { return getWidenedTypeOfArrayLiteral(type); } return type; + + function getWidenedTypeOfObjectLiteral(type: Type): Type { + var properties = getPropertiesOfType(type); + if (properties.length) { + var widenedTypes: Type[] = []; + var propTypeWasWidened: boolean = false; + forEach(properties, p => { + var propType = getTypeOfSymbol(p); + var widenedType = getWidenedType(propType); + if (propType !== widenedType) { + propTypeWasWidened = true; + + if (!supressNoImplicitAnyErrors && program.getCompilerOptions().noImplicitAny && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { + error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(widenedType)); + } + } + widenedTypes.push(widenedType); + }); + if (propTypeWasWidened) { + var members: SymbolTable = {}; + var index = 0; + forEach(properties, p => { + var symbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, p.name); + symbol.declarations = p.declarations; + symbol.parent = p.parent; + symbol.type = widenedTypes[index++]; + symbol.target = p; + if (p.valueDeclaration) symbol.valueDeclaration = p.valueDeclaration; + members[symbol.name] = symbol; + }); + var stringIndexType = getIndexTypeOfType(type, IndexKind.String); + var numberIndexType = getIndexTypeOfType(type, IndexKind.Number); + if (stringIndexType) stringIndexType = getWidenedType(stringIndexType); + if (numberIndexType) numberIndexType = getWidenedType(numberIndexType); + type = createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexType, numberIndexType); + } + } + return type; + } + + function getWidenedTypeOfArrayLiteral(type: Type): Type { + var elementType = (type).typeArguments[0]; + var widenedType = getWidenedType(elementType, supressNoImplicitAnyErrors); + + type = elementType !== widenedType ? createArrayType(widenedType) : type; + + return type; + } } function forEachMatchingParameterType(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) { @@ -4329,7 +4329,7 @@ module ts { var exprType = checkExpression(node.operand); var targetType = getTypeFromTypeNode(node.type); if (fullTypeCheck && targetType !== unknownType) { - var widenedType = getWidenedType(exprType); + var widenedType = getWidenedType(exprType, /*supressNoImplicitAnyErrors*/ true); if (!(isTypeAssignableTo(targetType, widenedType))) { checkTypeAssignableTo(exprType, targetType, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other_Colon, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other); } diff --git a/tests/baselines/reference/noImplicitAnyInCastExpression.errors.txt b/tests/baselines/reference/noImplicitAnyInCastExpression.errors.txt new file mode 100644 index 00000000000..bc7542df511 --- /dev/null +++ b/tests/baselines/reference/noImplicitAnyInCastExpression.errors.txt @@ -0,0 +1,20 @@ +==== tests/cases/compiler/noImplicitAnyInCastExpression.ts (1 errors) ==== + + // verify no noImplictAny errors reported with cast expression + + interface IFoo { + a: number; + b: string; + } + + // Expr type not assignable to target type + ({ a: null }); + + // Expr type assignable to target type + ({ a: 2, b: undefined }); + + // Neither types is assignable to each other + ({ c: null }); + ~~~~~~~~~~~~~~~~~ +!!! Neither type '{ c: null; }' nor type 'IFoo' is assignable to the other: +!!! Property 'a' is missing in type '{ c: null; }'. \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitAnyInCastExpression.js b/tests/baselines/reference/noImplicitAnyInCastExpression.js new file mode 100644 index 00000000000..1b7cc59c7c0 --- /dev/null +++ b/tests/baselines/reference/noImplicitAnyInCastExpression.js @@ -0,0 +1,26 @@ +//// [noImplicitAnyInCastExpression.ts] + +// verify no noImplictAny errors reported with cast expression + +interface IFoo { + a: number; + b: string; +} + +// Expr type not assignable to target type +({ a: null }); + +// Expr type assignable to target type +({ a: 2, b: undefined }); + +// Neither types is assignable to each other +({ c: null }); + +//// [noImplicitAnyInCastExpression.js] +// verify no noImplictAny errors reported with cast expression +// Expr type not assignable to target type +{ a: null }; +// Expr type assignable to target type +{ a: 2, b: undefined }; +// Neither types is assignable to each other +{ c: null }; diff --git a/tests/cases/compiler/noImplicitAnyInCastExpression.ts b/tests/cases/compiler/noImplicitAnyInCastExpression.ts new file mode 100644 index 00000000000..5566b898a07 --- /dev/null +++ b/tests/cases/compiler/noImplicitAnyInCastExpression.ts @@ -0,0 +1,17 @@ +//@noImplicitAny: true + +// verify no noImplictAny errors reported with cast expression + +interface IFoo { + a: number; + b: string; +} + +// Expr type not assignable to target type +({ a: null }); + +// Expr type assignable to target type +({ a: 2, b: undefined }); + +// Neither types is assignable to each other +({ c: null }); \ No newline at end of file