diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ace3d5ee8cfe2..78df7551bf881 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9370,25 +9370,6 @@ namespace ts { return type.resolvedProperties; } - function getPossiblePropertiesOfUnionType(type: UnionType): Symbol[] { - if (type.possiblePropertyCache) { - return type.possiblePropertyCache.size ? arrayFrom(type.possiblePropertyCache.values()) : emptyArray; - } - type.possiblePropertyCache = createSymbolTable(); - for (const t of type.types) { - for (const p of getPropertiesOfType(t)) { - if (!type.possiblePropertyCache.has(p.escapedName)) { - const prop = getUnionOrIntersectionProperty(type, p.escapedName); - if (prop) { - type.possiblePropertyCache.set(p.escapedName, prop); - } - } - } - } - // We can't simply use the normal property cache here, since that will contain cached apparent type members :( - return type.possiblePropertyCache.size ? arrayFrom(type.possiblePropertyCache.values()) : emptyArray; - } - function getPropertiesOfType(type: Type): Symbol[] { type = getApparentType(type); return type.flags & TypeFlags.UnionOrIntersection ? @@ -14614,8 +14595,7 @@ namespace ts { const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); const isPerformingExcessPropertyChecks = !isApparentIntersectionConstituent && (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral); if (isPerformingExcessPropertyChecks) { - const discriminantType = target.flags & TypeFlags.Union ? findMatchingDiscriminantType(source, target as UnionType) : undefined; - if (hasExcessProperties(source, target, discriminantType, reportErrors)) { + if (hasExcessProperties(source, target, reportErrors)) { if (reportErrors) { reportRelationError(headMessage, source, target); } @@ -14657,13 +14637,6 @@ namespace ts { else { if (target.flags & TypeFlags.Union) { result = typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive)); - if (result && (isPerformingExcessPropertyChecks || isPerformingCommonPropertyChecks)) { - // Validate against excess props using the original `source` - const discriminantType = findMatchingDiscriminantType(source, target as UnionType) || filterPrimitivesIfContainsNonPrimitive(target as UnionType); - if (!propertiesRelatedTo(source, discriminantType, reportErrors, /*excludedProperties*/ undefined, isIntersectionConstituent)) { - return Ternary.False; - } - } } else if (target.flags & TypeFlags.Intersection) { isIntersectionConstituent = true; // set here to affect the following trio of checks @@ -14776,26 +14749,38 @@ namespace ts { return Ternary.False; } - function hasExcessProperties(source: FreshObjectLiteralType, target: Type, discriminant: Type | undefined, reportErrors: boolean): boolean { - if (!noImplicitAny && getObjectFlags(target) & ObjectFlags.JSLiteral) { + function getTypeOfPropertyInTypes(types: Type[], name: __String) { + const appendPropType = (propTypes: Type[] | undefined, type: Type) => { + type = getApparentType(type); + const prop = type.flags & TypeFlags.UnionOrIntersection ? getPropertyOfUnionOrIntersectionType(type, name) : getPropertyOfObjectType(type, name); + const propType = prop && getTypeOfSymbol(prop) || isNumericLiteralName(name) && getIndexTypeOfType(type, IndexKind.Number) || getIndexTypeOfType(type, IndexKind.String) || undefinedType; + return append(propTypes, propType); + }; + return getUnionType(reduceLeft(types, appendPropType, /*initial*/ undefined) || emptyArray); + } + + function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { + if (!isExcessPropertyCheckTarget(target) || !noImplicitAny && getObjectFlags(target) & ObjectFlags.JSLiteral) { return false; // Disable excess property checks on JS literals to simulate having an implicit "index signature" - but only outside of noImplicitAny } - if (isExcessPropertyCheckTarget(target)) { - const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); - if ((relation === assignableRelation || relation === comparableRelation) && - (isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) { - return false; - } - if (discriminant) { - // check excess properties against discriminant type only, not the entire union - return hasExcessProperties(source, discriminant, /*discriminant*/ undefined, reportErrors); - } - for (const prop of getPropertiesOfType(source)) { - if (shouldCheckAsExcessProperty(prop, source.symbol) && !isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) { + const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); + if ((relation === assignableRelation || relation === comparableRelation) && + (isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) { + return false; + } + let reducedTarget = target; + let checkTypes: Type[] | undefined; + if (target.flags & TypeFlags.Union) { + reducedTarget = findMatchingDiscriminantType(source, target) || filterPrimitivesIfContainsNonPrimitive(target); + checkTypes = reducedTarget.flags & TypeFlags.Union ? (reducedTarget).types : [reducedTarget]; + } + for (const prop of getPropertiesOfType(source)) { + if (shouldCheckAsExcessProperty(prop, source.symbol)) { + if (!isKnownProperty(reducedTarget, prop.escapedName, isComparingJsxAttributes)) { if (reportErrors) { // Report error in terms of object types in the target as those are the only ones // we check in isKnownProperty. - const errorTarget = filterType(target, isExcessPropertyCheckTarget); + const errorTarget = filterType(reducedTarget, isExcessPropertyCheckTarget); // We know *exactly* where things went wrong when comparing the types. // Use this property as the error node as this will be more helpful in // reasoning about what went wrong. @@ -14826,7 +14811,6 @@ namespace ts { suggestion = getSuggestionForNonexistentProperty(name, errorTarget); } } - if (suggestion !== undefined) { reportError(Diagnostics.Object_literal_may_only_specify_known_properties_but_0_does_not_exist_in_type_1_Did_you_mean_to_write_2, symbolToString(prop), typeToString(errorTarget), suggestion); @@ -14839,6 +14823,12 @@ namespace ts { } return true; } + if (checkTypes && !isRelatedTo(getTypeOfSymbol(prop), getTypeOfPropertyInTypes(checkTypes, prop.escapedName), reportErrors)) { + if (reportErrors) { + reportIncompatibleError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(prop)); + } + return true; + } } } return false; @@ -15839,7 +15829,7 @@ namespace ts { } // We only call this for union target types when we're attempting to do excess property checking - in those cases, we want to get _all possible props_ // from the target union, across all members - const properties = target.flags & TypeFlags.Union ? getPossiblePropertiesOfUnionType(target as UnionType) : getPropertiesOfType(target); + const properties = getPropertiesOfType(target); const numericNamesOnly = isTupleType(source) && isTupleType(target); for (const targetProp of excludeProperties(properties, excludedProperties)) { const name = targetProp.escapedName; @@ -17344,7 +17334,7 @@ namespace ts { } function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): IterableIterator { - const properties = target.flags & TypeFlags.Union ? getPossiblePropertiesOfUnionType(target as UnionType) : getPropertiesOfType(target); + const properties = getPropertiesOfType(target); for (const targetProp of properties) { if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial)) { const sourceProp = getPropertyOfType(source, targetProp.escapedName); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 08cc7343ccaea..4c33bf68b4b48 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4483,8 +4483,6 @@ namespace ts { } export interface UnionType extends UnionOrIntersectionType { - /* @internal */ - possiblePropertyCache?: SymbolTable; // Cache of _all_ resolved properties less any from aparent members } export interface IntersectionType extends UnionOrIntersectionType { diff --git a/tests/baselines/reference/deepExcessPropertyCheckingWhenTargetIsIntersection.errors.txt b/tests/baselines/reference/deepExcessPropertyCheckingWhenTargetIsIntersection.errors.txt index 1f2552d47f271..975f2a37d3863 100644 --- a/tests/baselines/reference/deepExcessPropertyCheckingWhenTargetIsIntersection.errors.txt +++ b/tests/baselines/reference/deepExcessPropertyCheckingWhenTargetIsIntersection.errors.txt @@ -1,8 +1,9 @@ tests/cases/compiler/deepExcessPropertyCheckingWhenTargetIsIntersection.ts(21,33): error TS2322: Type '{ INVALID_PROP_NAME: string; ariaLabel: string; }' is not assignable to type 'ITestProps'. Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'ITestProps'. -tests/cases/compiler/deepExcessPropertyCheckingWhenTargetIsIntersection.ts(27,34): error TS2200: The types of 'icon.props' are incompatible between these types. - Type '{ INVALID_PROP_NAME: string; ariaLabel: string; }' is not assignable to type 'ITestProps'. - Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'ITestProps'. +tests/cases/compiler/deepExcessPropertyCheckingWhenTargetIsIntersection.ts(27,34): error TS2345: Argument of type '{ icon: { props: { INVALID_PROP_NAME: string; ariaLabel: string; }; }; }' is not assignable to parameter of type '(TestProps & { children?: number; }) | ({ props2: { x: number; }; } & { children?: number; })'. + The types of 'icon.props' are incompatible between these types. + Type '{ INVALID_PROP_NAME: string; ariaLabel: string; }' is not assignable to type 'ITestProps'. + Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'ITestProps'. ==== tests/cases/compiler/deepExcessPropertyCheckingWhenTargetIsIntersection.ts (2 errors) ==== @@ -38,7 +39,8 @@ tests/cases/compiler/deepExcessPropertyCheckingWhenTargetIsIntersection.ts(27,34 TestComponent2({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }}); ~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2200: The types of 'icon.props' are incompatible between these types. -!!! error TS2200: Type '{ INVALID_PROP_NAME: string; ariaLabel: string; }' is not assignable to type 'ITestProps'. -!!! error TS2200: Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'ITestProps'. +!!! error TS2345: Argument of type '{ icon: { props: { INVALID_PROP_NAME: string; ariaLabel: string; }; }; }' is not assignable to parameter of type '(TestProps & { children?: number; }) | ({ props2: { x: number; }; } & { children?: number; })'. +!!! error TS2345: The types of 'icon.props' are incompatible between these types. +!!! error TS2345: Type '{ INVALID_PROP_NAME: string; ariaLabel: string; }' is not assignable to type 'ITestProps'. +!!! error TS2345: Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'ITestProps'. \ No newline at end of file diff --git a/tests/baselines/reference/discriminateObjectTypesOnly.errors.txt b/tests/baselines/reference/discriminateObjectTypesOnly.errors.txt deleted file mode 100644 index efe5bf4ccedb2..0000000000000 --- a/tests/baselines/reference/discriminateObjectTypesOnly.errors.txt +++ /dev/null @@ -1,17 +0,0 @@ -tests/cases/compiler/discriminateObjectTypesOnly.ts(9,7): error TS2741: Property 'toFixed' is missing in type '{ toString: undefined; }' but required in type '{ toFixed: null; toString: undefined; }'. - - -==== tests/cases/compiler/discriminateObjectTypesOnly.ts (1 errors) ==== - type Thing = number | object; - const k: Thing = { toFixed: null }; // OK, satisfies object - - type Thing2 = number | { toFixed: null } | object; - const q: Thing2 = { toFixed: null }; - const h: Thing2 = { toString: null }; // OK, satisfies object - - type Thing3 = number | { toFixed: null, toString: undefined } | object; - const l: Thing3 = { toString: undefined }; // error, toFixed isn't null - ~ -!!! error TS2741: Property 'toFixed' is missing in type '{ toString: undefined; }' but required in type '{ toFixed: null; toString: undefined; }'. -!!! related TS2728 tests/cases/compiler/discriminateObjectTypesOnly.ts:8:26: 'toFixed' is declared here. - \ No newline at end of file diff --git a/tests/baselines/reference/errorsOnUnionsOfOverlappingObjects01.errors.txt b/tests/baselines/reference/errorsOnUnionsOfOverlappingObjects01.errors.txt index 1b8dab19b5b41..38ae9542a4060 100644 --- a/tests/baselines/reference/errorsOnUnionsOfOverlappingObjects01.errors.txt +++ b/tests/baselines/reference/errorsOnUnionsOfOverlappingObjects01.errors.txt @@ -3,9 +3,8 @@ tests/cases/compiler/errorsOnUnionsOfOverlappingObjects01.ts(18,3): error TS2345 Types of property 'b' are incompatible. Type 'string' is not assignable to type 'number'. tests/cases/compiler/errorsOnUnionsOfOverlappingObjects01.ts(19,3): error TS2345: Argument of type '{ a: string; b: string; }' is not assignable to parameter of type 'Foo | Other'. - Type '{ a: string; b: string; }' is not assignable to type 'Foo'. - Types of property 'b' are incompatible. - Type 'string' is not assignable to type 'number'. + Types of property 'b' are incompatible. + Type 'string' is not assignable to type 'number'. tests/cases/compiler/errorsOnUnionsOfOverlappingObjects01.ts(24,5): error TS2345: Argument of type '{ a: string; b: string; }' is not assignable to parameter of type 'Bar | Other'. Object literal may only specify known properties, and 'a' does not exist in type 'Bar | Other'. tests/cases/compiler/errorsOnUnionsOfOverlappingObjects01.ts(42,10): error TS2345: Argument of type '{ dog: string; }' is not assignable to parameter of type 'ExoticAnimal'. @@ -45,9 +44,8 @@ tests/cases/compiler/errorsOnUnionsOfOverlappingObjects01.ts(47,10): error TS234 f({ a: '', b: '' }) ~~~~~~~~~~~~~~~~ !!! error TS2345: Argument of type '{ a: string; b: string; }' is not assignable to parameter of type 'Foo | Other'. -!!! error TS2345: Type '{ a: string; b: string; }' is not assignable to type 'Foo'. -!!! error TS2345: Types of property 'b' are incompatible. -!!! error TS2345: Type 'string' is not assignable to type 'number'. +!!! error TS2345: Types of property 'b' are incompatible. +!!! error TS2345: Type 'string' is not assignable to type 'number'. declare function g(x: Bar | Other): any; diff --git a/tests/baselines/reference/excessPropertyCheckWithUnions.errors.txt b/tests/baselines/reference/excessPropertyCheckWithUnions.errors.txt index 72da324caf759..0d56383ed9a2f 100644 --- a/tests/baselines/reference/excessPropertyCheckWithUnions.errors.txt +++ b/tests/baselines/reference/excessPropertyCheckWithUnions.errors.txt @@ -20,14 +20,24 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(49,35): error TS2322: Type Object literal may only specify known properties, and 'second' does not exist in type '{ a: 1; b: 1; first: string; }'. tests/cases/compiler/excessPropertyCheckWithUnions.ts(50,35): error TS2322: Type '{ a: 1; b: 1; first: string; third: string; }' is not assignable to type 'Overlapping'. Object literal may only specify known properties, and 'third' does not exist in type '{ a: 1; b: 1; first: string; }'. -tests/cases/compiler/excessPropertyCheckWithUnions.ts(66,9): error TS2326: Types of property 'n' are incompatible. - Type '{ a: string; b: string; }' is not assignable to type 'AN'. - Object literal may only specify known properties, and 'b' does not exist in type 'AN'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(66,9): error TS2322: Type '{ kind: "A"; n: { a: string; b: string; }; }' is not assignable to type 'AB'. + Types of property 'n' are incompatible. + Type '{ a: string; b: string; }' is not assignable to type 'AN'. + Object literal may only specify known properties, and 'b' does not exist in type 'AN'. tests/cases/compiler/excessPropertyCheckWithUnions.ts(87,5): error TS2322: Type '{ tag: "button"; type: "submit"; href: string; }' is not assignable to type 'Union'. Object literal may only specify known properties, and 'href' does not exist in type 'Button'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(107,7): error TS2322: Type '{ foo: string; }' is not assignable to type 'ObjectDataSpecification'. + Types of property 'foo' are incompatible. + Type 'string' is not assignable to type 'IValue | undefined'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(113,7): error TS2322: Type '{ a: string; }' is not assignable to type '{ [x: string]: number; } | { [x: number]: number; }'. + Types of property 'a' are incompatible. + Type 'string' is not assignable to type 'number | undefined'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(114,7): error TS2322: Type '{ a: number; c: string; }' is not assignable to type '{ [x: string]: number; } | { a: number; }'. + Types of property 'c' are incompatible. + Type 'string' is not assignable to type 'number | undefined'. -==== tests/cases/compiler/excessPropertyCheckWithUnions.ts (11 errors) ==== +==== tests/cases/compiler/excessPropertyCheckWithUnions.ts (14 errors) ==== type ADT = { tag: "A", a1: string @@ -127,9 +137,10 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(87,5): error TS2322: Type a: "a", b: "b", // excess -- kind: "A" ~~~~~~ -!!! error TS2326: Types of property 'n' are incompatible. -!!! error TS2326: Type '{ a: string; b: string; }' is not assignable to type 'AN'. -!!! error TS2326: Object literal may only specify known properties, and 'b' does not exist in type 'AN'. +!!! error TS2322: Type '{ kind: "A"; n: { a: string; b: string; }; }' is not assignable to type 'AB'. +!!! error TS2322: Types of property 'n' are incompatible. +!!! error TS2322: Type '{ a: string; b: string; }' is not assignable to type 'AN'. +!!! error TS2322: Object literal may only specify known properties, and 'b' does not exist in type 'AN'. } } const abac: AB = { @@ -155,4 +166,42 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(87,5): error TS2322: Type !!! error TS2322: Type '{ tag: "button"; type: "submit"; href: string; }' is not assignable to type 'Union'. !!! error TS2322: Object literal may only specify known properties, and 'href' does not exist in type 'Button'. }; + + // Repro from #34611 + + interface IValue { + value: string + } + + interface StringKeys { + [propertyName: string]: IValue; + }; + + interface NumberKeys { + [propertyName: number]: IValue; + } + + type ObjectDataSpecification = StringKeys | NumberKeys; + + + const dataSpecification: ObjectDataSpecification = { // Error + ~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ foo: string; }' is not assignable to type 'ObjectDataSpecification'. +!!! error TS2322: Types of property 'foo' are incompatible. +!!! error TS2322: Type 'string' is not assignable to type 'IValue | undefined'. + foo: "asdfsadffsd" + }; + + // Repro from #34611 + + const obj1: { [x: string]: number } | { [x: number]: number } = { a: 'abc' }; // Error + ~~~~ +!!! error TS2322: Type '{ a: string; }' is not assignable to type '{ [x: string]: number; } | { [x: number]: number; }'. +!!! error TS2322: Types of property 'a' are incompatible. +!!! error TS2322: Type 'string' is not assignable to type 'number | undefined'. + const obj2: { [x: string]: number } | { a: number } = { a: 5, c: 'abc' }; // Error + ~~~~ +!!! error TS2322: Type '{ a: number; c: string; }' is not assignable to type '{ [x: string]: number; } | { a: number; }'. +!!! error TS2322: Types of property 'c' are incompatible. +!!! error TS2322: Type 'string' is not assignable to type 'number | undefined'. \ No newline at end of file diff --git a/tests/baselines/reference/excessPropertyCheckWithUnions.js b/tests/baselines/reference/excessPropertyCheckWithUnions.js index 691a64f65b808..34cd337705a34 100644 --- a/tests/baselines/reference/excessPropertyCheckWithUnions.js +++ b/tests/baselines/reference/excessPropertyCheckWithUnions.js @@ -87,6 +87,32 @@ const obj: Union = { // should have error here href: 'foo', }; + +// Repro from #34611 + +interface IValue { + value: string +} + +interface StringKeys { + [propertyName: string]: IValue; +}; + +interface NumberKeys { + [propertyName: number]: IValue; +} + +type ObjectDataSpecification = StringKeys | NumberKeys; + + +const dataSpecification: ObjectDataSpecification = { // Error + foo: "asdfsadffsd" +}; + +// Repro from #34611 + +const obj1: { [x: string]: number } | { [x: number]: number } = { a: 'abc' }; // Error +const obj2: { [x: string]: number } | { a: number } = { a: 5, c: 'abc' }; // Error //// [excessPropertyCheckWithUnions.js] @@ -144,3 +170,10 @@ var obj = { // should have error here href: 'foo' }; +; +var dataSpecification = { + foo: "asdfsadffsd" +}; +// Repro from #34611 +var obj1 = { a: 'abc' }; // Error +var obj2 = { a: 5, c: 'abc' }; // Error diff --git a/tests/baselines/reference/excessPropertyCheckWithUnions.symbols b/tests/baselines/reference/excessPropertyCheckWithUnions.symbols index 749e359d4a1cc..8fb86125a5731 100644 --- a/tests/baselines/reference/excessPropertyCheckWithUnions.symbols +++ b/tests/baselines/reference/excessPropertyCheckWithUnions.symbols @@ -254,3 +254,59 @@ const obj: Union = { }; +// Repro from #34611 + +interface IValue { +>IValue : Symbol(IValue, Decl(excessPropertyCheckWithUnions.ts, 87, 2)) + + value: string +>value : Symbol(IValue.value, Decl(excessPropertyCheckWithUnions.ts, 91, 18)) +} + +interface StringKeys { +>StringKeys : Symbol(StringKeys, Decl(excessPropertyCheckWithUnions.ts, 93, 1)) + + [propertyName: string]: IValue; +>propertyName : Symbol(propertyName, Decl(excessPropertyCheckWithUnions.ts, 96, 5)) +>IValue : Symbol(IValue, Decl(excessPropertyCheckWithUnions.ts, 87, 2)) + +}; + +interface NumberKeys { +>NumberKeys : Symbol(NumberKeys, Decl(excessPropertyCheckWithUnions.ts, 97, 2)) + + [propertyName: number]: IValue; +>propertyName : Symbol(propertyName, Decl(excessPropertyCheckWithUnions.ts, 100, 5)) +>IValue : Symbol(IValue, Decl(excessPropertyCheckWithUnions.ts, 87, 2)) +} + +type ObjectDataSpecification = StringKeys | NumberKeys; +>ObjectDataSpecification : Symbol(ObjectDataSpecification, Decl(excessPropertyCheckWithUnions.ts, 101, 1)) +>StringKeys : Symbol(StringKeys, Decl(excessPropertyCheckWithUnions.ts, 93, 1)) +>NumberKeys : Symbol(NumberKeys, Decl(excessPropertyCheckWithUnions.ts, 97, 2)) + + +const dataSpecification: ObjectDataSpecification = { // Error +>dataSpecification : Symbol(dataSpecification, Decl(excessPropertyCheckWithUnions.ts, 106, 5)) +>ObjectDataSpecification : Symbol(ObjectDataSpecification, Decl(excessPropertyCheckWithUnions.ts, 101, 1)) + + foo: "asdfsadffsd" +>foo : Symbol(foo, Decl(excessPropertyCheckWithUnions.ts, 106, 52)) + +}; + +// Repro from #34611 + +const obj1: { [x: string]: number } | { [x: number]: number } = { a: 'abc' }; // Error +>obj1 : Symbol(obj1, Decl(excessPropertyCheckWithUnions.ts, 112, 5)) +>x : Symbol(x, Decl(excessPropertyCheckWithUnions.ts, 112, 15)) +>x : Symbol(x, Decl(excessPropertyCheckWithUnions.ts, 112, 41)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 112, 65)) + +const obj2: { [x: string]: number } | { a: number } = { a: 5, c: 'abc' }; // Error +>obj2 : Symbol(obj2, Decl(excessPropertyCheckWithUnions.ts, 113, 5)) +>x : Symbol(x, Decl(excessPropertyCheckWithUnions.ts, 113, 15)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 113, 39)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 113, 55)) +>c : Symbol(c, Decl(excessPropertyCheckWithUnions.ts, 113, 61)) + diff --git a/tests/baselines/reference/excessPropertyCheckWithUnions.types b/tests/baselines/reference/excessPropertyCheckWithUnions.types index f56aa287daa7e..38e9a6c81e7a4 100644 --- a/tests/baselines/reference/excessPropertyCheckWithUnions.types +++ b/tests/baselines/reference/excessPropertyCheckWithUnions.types @@ -312,3 +312,55 @@ const obj: Union = { }; +// Repro from #34611 + +interface IValue { + value: string +>value : string +} + +interface StringKeys { + [propertyName: string]: IValue; +>propertyName : string + +}; + +interface NumberKeys { + [propertyName: number]: IValue; +>propertyName : number +} + +type ObjectDataSpecification = StringKeys | NumberKeys; +>ObjectDataSpecification : ObjectDataSpecification + + +const dataSpecification: ObjectDataSpecification = { // Error +>dataSpecification : ObjectDataSpecification +>{ // Error foo: "asdfsadffsd"} : { foo: string; } + + foo: "asdfsadffsd" +>foo : string +>"asdfsadffsd" : "asdfsadffsd" + +}; + +// Repro from #34611 + +const obj1: { [x: string]: number } | { [x: number]: number } = { a: 'abc' }; // Error +>obj1 : { [x: string]: number; } | { [x: number]: number; } +>x : string +>x : number +>{ a: 'abc' } : { a: string; } +>a : string +>'abc' : "abc" + +const obj2: { [x: string]: number } | { a: number } = { a: 5, c: 'abc' }; // Error +>obj2 : { [x: string]: number; } | { a: number; } +>x : string +>a : number +>{ a: 5, c: 'abc' } : { a: number; c: string; } +>a : number +>5 : 5 +>c : string +>'abc' : "abc" + diff --git a/tests/baselines/reference/mappedTypeIndexedAccess.errors.txt b/tests/baselines/reference/mappedTypeIndexedAccess.errors.txt index 24eae941c61bd..070f48c216af7 100644 --- a/tests/baselines/reference/mappedTypeIndexedAccess.errors.txt +++ b/tests/baselines/reference/mappedTypeIndexedAccess.errors.txt @@ -1,11 +1,9 @@ tests/cases/compiler/mappedTypeIndexedAccess.ts(18,5): error TS2322: Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; } | { key: "bar"; value: number; }'. - Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; }'. - Types of property 'value' are incompatible. - Type 'number' is not assignable to type 'string'. + Types of property 'value' are incompatible. + Type 'number' is not assignable to type 'string'. tests/cases/compiler/mappedTypeIndexedAccess.ts(24,5): error TS2322: Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; } | { key: "bar"; value: number; }'. - Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; }'. - Types of property 'value' are incompatible. - Type 'number' is not assignable to type 'string'. + Types of property 'value' are incompatible. + Type 'number' is not assignable to type 'string'. ==== tests/cases/compiler/mappedTypeIndexedAccess.ts (2 errors) ==== @@ -29,9 +27,8 @@ tests/cases/compiler/mappedTypeIndexedAccess.ts(24,5): error TS2322: Type '{ key let pair1: Pair = { ~~~~~ !!! error TS2322: Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; } | { key: "bar"; value: number; }'. -!!! error TS2322: Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; }'. -!!! error TS2322: Types of property 'value' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! error TS2322: Types of property 'value' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. key: "foo", value: 3 }; @@ -40,9 +37,8 @@ tests/cases/compiler/mappedTypeIndexedAccess.ts(24,5): error TS2322: Type '{ key let pair2: Pairs[keyof FooBar] = { ~~~~~ !!! error TS2322: Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; } | { key: "bar"; value: number; }'. -!!! error TS2322: Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; }'. -!!! error TS2322: Types of property 'value' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! error TS2322: Types of property 'value' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. key: "foo", value: 3 }; diff --git a/tests/baselines/reference/nonObjectUnionNestedExcessPropertyCheck.errors.txt b/tests/baselines/reference/nonObjectUnionNestedExcessPropertyCheck.errors.txt index 4cf8a99e0eafb..55cc7ea4c91b6 100644 --- a/tests/baselines/reference/nonObjectUnionNestedExcessPropertyCheck.errors.txt +++ b/tests/baselines/reference/nonObjectUnionNestedExcessPropertyCheck.errors.txt @@ -1,12 +1,13 @@ tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts(13,35): error TS2322: Type '{ INVALID_PROP_NAME: string; iconProp: string; }' is not assignable to type 'number | IProps'. Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'IProps'. -tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts(16,7): error TS2322: Type '{ nestedProp: { asdfasdf: string; }; iconProp: string; }' is not assignable to type 'number | IProps'. - Type '{ nestedProp: { asdfasdf: string; }; iconProp: string; }' is not assignable to type 'IProps'. - Types of property 'nestedProp' are incompatible. - Type '{ asdfasdf: string; }' has no properties in common with type '{ testBool?: boolean; }'. -tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts(19,56): error TS2326: Types of property 'nestedProps' are incompatible. - Type '{ INVALID_PROP_NAME: string; iconProp: string; }' is not assignable to type 'IProps'. - Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'IProps'. +tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts(16,49): error TS2322: Type '{ nestedProp: { asdfasdf: string; }; iconProp: string; }' is not assignable to type 'number | IProps'. + Types of property 'nestedProp' are incompatible. + Type '{ asdfasdf: string; }' is not assignable to type '{ testBool?: boolean; }'. + Object literal may only specify known properties, and 'asdfasdf' does not exist in type '{ testBool?: boolean; }'. +tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts(19,56): error TS2322: Type '{ nestedProps: { INVALID_PROP_NAME: string; iconProp: string; }; }' is not assignable to type 'number | INestedProps'. + Types of property 'nestedProps' are incompatible. + Type '{ INVALID_PROP_NAME: string; iconProp: string; }' is not assignable to type 'IProps'. + Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'IProps'. ==== tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts (3 errors) ==== @@ -29,16 +30,17 @@ tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts(19,56): error TS // Nested typing works here and we also get an expected error: const propB2: IProps | number = { nestedProp: { asdfasdf: 'test' }, iconProp: 'test' }; - ~~~~~~ + ~~~~~~~~~~~~~~~~ !!! error TS2322: Type '{ nestedProp: { asdfasdf: string; }; iconProp: string; }' is not assignable to type 'number | IProps'. -!!! error TS2322: Type '{ nestedProp: { asdfasdf: string; }; iconProp: string; }' is not assignable to type 'IProps'. -!!! error TS2322: Types of property 'nestedProp' are incompatible. -!!! error TS2322: Type '{ asdfasdf: string; }' has no properties in common with type '{ testBool?: boolean; }'. +!!! error TS2322: Types of property 'nestedProp' are incompatible. +!!! error TS2322: Type '{ asdfasdf: string; }' is not assignable to type '{ testBool?: boolean; }'. +!!! error TS2322: Object literal may only specify known properties, and 'asdfasdf' does not exist in type '{ testBool?: boolean; }'. // Want an error generated here but there isn't one. const propA1: INestedProps | number = { nestedProps: { INVALID_PROP_NAME: 'share', iconProp: 'test' } }; ~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2326: Types of property 'nestedProps' are incompatible. -!!! error TS2326: Type '{ INVALID_PROP_NAME: string; iconProp: string; }' is not assignable to type 'IProps'. -!!! error TS2326: Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'IProps'. +!!! error TS2322: Type '{ nestedProps: { INVALID_PROP_NAME: string; iconProp: string; }; }' is not assignable to type 'number | INestedProps'. +!!! error TS2322: Types of property 'nestedProps' are incompatible. +!!! error TS2322: Type '{ INVALID_PROP_NAME: string; iconProp: string; }' is not assignable to type 'IProps'. +!!! error TS2322: Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'IProps'. \ No newline at end of file diff --git a/tests/baselines/reference/objectLiteralsAgainstUnionsOfArrays01.errors.txt b/tests/baselines/reference/objectLiteralsAgainstUnionsOfArrays01.errors.txt index 5260d6a8da6d3..2959f29bbc984 100644 --- a/tests/baselines/reference/objectLiteralsAgainstUnionsOfArrays01.errors.txt +++ b/tests/baselines/reference/objectLiteralsAgainstUnionsOfArrays01.errors.txt @@ -1,7 +1,6 @@ tests/cases/compiler/objectLiteralsAgainstUnionsOfArrays01.ts(10,5): error TS2322: Type '{ prop: number; }' is not assignable to type 'Bar | Bar[]'. - Type '{ prop: number; }' is not assignable to type 'Bar'. - Types of property 'prop' are incompatible. - Type 'number' is not assignable to type 'string'. + Types of property 'prop' are incompatible. + Type 'number' is not assignable to type 'string'. ==== tests/cases/compiler/objectLiteralsAgainstUnionsOfArrays01.ts (1 errors) ==== @@ -17,9 +16,8 @@ tests/cases/compiler/objectLiteralsAgainstUnionsOfArrays01.ts(10,5): error TS232 { bar: { prop: 100 } } ~~~ !!! error TS2322: Type '{ prop: number; }' is not assignable to type 'Bar | Bar[]'. -!!! error TS2322: Type '{ prop: number; }' is not assignable to type 'Bar'. -!!! error TS2322: Types of property 'prop' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! error TS2322: Types of property 'prop' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. !!! related TS6500 tests/cases/compiler/objectLiteralsAgainstUnionsOfArrays01.ts:2:3: The expected type comes from property 'bar' which is declared here on type 'Foo' ] \ No newline at end of file diff --git a/tests/cases/compiler/excessPropertyCheckWithUnions.ts b/tests/cases/compiler/excessPropertyCheckWithUnions.ts index bb3e59151fc2a..635c5c2a7d3f6 100644 --- a/tests/cases/compiler/excessPropertyCheckWithUnions.ts +++ b/tests/cases/compiler/excessPropertyCheckWithUnions.ts @@ -87,3 +87,29 @@ const obj: Union = { // should have error here href: 'foo', }; + +// Repro from #34611 + +interface IValue { + value: string +} + +interface StringKeys { + [propertyName: string]: IValue; +}; + +interface NumberKeys { + [propertyName: number]: IValue; +} + +type ObjectDataSpecification = StringKeys | NumberKeys; + + +const dataSpecification: ObjectDataSpecification = { // Error + foo: "asdfsadffsd" +}; + +// Repro from #34611 + +const obj1: { [x: string]: number } | { [x: number]: number } = { a: 'abc' }; // Error +const obj2: { [x: string]: number } | { a: number } = { a: 5, c: 'abc' }; // Error