mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-10 10:58:20 -05:00
Merge pull request #28854 from Microsoft/fixExcessPropertyChecks
Improve excess property checks
This commit is contained in:
@@ -11835,7 +11835,7 @@ namespace ts {
|
||||
if (!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 (maybeTypeOfKind(target, TypeFlags.Object) && !(getObjectFlags(target) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) {
|
||||
if (isExcessPropertyCheckTarget(target)) {
|
||||
const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
|
||||
if ((relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) &&
|
||||
(isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) {
|
||||
@@ -11848,6 +11848,9 @@ namespace ts {
|
||||
for (const prop of getPropertiesOfObjectType(source)) {
|
||||
if (shouldCheckAsExcessProperty(prop, source.symbol) && !isKnownProperty(target, 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);
|
||||
// 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.
|
||||
@@ -11856,7 +11859,7 @@ namespace ts {
|
||||
// JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal.
|
||||
// However, using an object-literal error message will be very confusing to the users so we give different a message.
|
||||
// TODO: Spelling suggestions for excess jsx attributes (needs new diagnostic messages)
|
||||
reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(prop), typeToString(target));
|
||||
reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(prop), typeToString(errorTarget));
|
||||
}
|
||||
else {
|
||||
// use the property's value declaration if the property is assigned inside the literal itself
|
||||
@@ -11870,17 +11873,17 @@ namespace ts {
|
||||
|
||||
const name = propDeclaration.name!;
|
||||
if (isIdentifier(name)) {
|
||||
suggestion = getSuggestionForNonexistentProperty(name, target);
|
||||
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(target), suggestion);
|
||||
symbolToString(prop), typeToString(errorTarget), suggestion);
|
||||
}
|
||||
else {
|
||||
reportError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1,
|
||||
symbolToString(prop), typeToString(target));
|
||||
symbolToString(prop), typeToString(errorTarget));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18598,20 +18601,23 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (targetType.flags & TypeFlags.UnionOrIntersection) {
|
||||
else if (targetType.flags & TypeFlags.UnionOrIntersection && isExcessPropertyCheckTarget(targetType)) {
|
||||
for (const t of (targetType as UnionOrIntersectionType).types) {
|
||||
if (isKnownProperty(t, name, isComparingJsxAttributes)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targetType.flags & TypeFlags.Conditional) {
|
||||
return isKnownProperty((targetType as ConditionalType).root.trueType, name, isComparingJsxAttributes) ||
|
||||
isKnownProperty((targetType as ConditionalType).root.falseType, name, isComparingJsxAttributes);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isExcessPropertyCheckTarget(type: Type): boolean {
|
||||
return !!(type.flags & TypeFlags.Object && !(getObjectFlags(type) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) ||
|
||||
type.flags & TypeFlags.NonPrimitive ||
|
||||
type.flags & TypeFlags.Union && some((<UnionType>type).types, isExcessPropertyCheckTarget) ||
|
||||
type.flags & TypeFlags.Intersection && every((<IntersectionType>type).types, isExcessPropertyCheckTarget));
|
||||
}
|
||||
|
||||
function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) {
|
||||
if (node.expression) {
|
||||
const type = checkExpression(node.expression, checkMode);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(8,5): error TS2322: Type '{ test: string; arg: A; }' is not assignable to type 'Something<A>'.
|
||||
Type '{ test: string; arg: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'.
|
||||
tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(9,33): error TS2322: Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'Something<A>'.
|
||||
Object literal may only specify known properties, and 'arr' does not exist in type 'Something<A>'.
|
||||
tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(9,5): error TS2322: Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'Something<A>'.
|
||||
Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts (2 errors) ====
|
||||
@@ -17,8 +17,8 @@ tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(9,
|
||||
!!! error TS2322: Type '{ test: string; arg: A; }' is not assignable to type 'Something<A>'.
|
||||
!!! error TS2322: Type '{ test: string; arg: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'.
|
||||
sa = { test: 'bye', arg: a, arr: a } // excess
|
||||
~~~~~~
|
||||
~~
|
||||
!!! error TS2322: Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'Something<A>'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'arr' does not exist in type 'Something<A>'.
|
||||
!!! error TS2322: Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'.
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(9,18): error TS2322: Type '{ forword: string; }' is not assignable to type 'Book'.
|
||||
Object literal may only specify known properties, but 'forword' does not exist in type 'Book'. Did you mean to write 'foreword'?
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(11,27): error TS2322: Type '{ foreward: string; }' is not assignable to type 'string | Book'.
|
||||
Object literal may only specify known properties, and 'foreward' does not exist in type 'string | Book'.
|
||||
Object literal may only specify known properties, but 'foreward' does not exist in type 'Book'. Did you mean to write 'foreword'?
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(13,53): error TS2322: Type '({ foreword: string; } | { forwards: string; })[]' is not assignable to type 'Book | Book[]'.
|
||||
Type '({ foreword: string; } | { forwards: string; })[]' is not assignable to type 'Book[]'.
|
||||
Type '{ foreword: string; } | { forwards: string; }' is not assignable to type 'Book'.
|
||||
@@ -13,17 +13,27 @@ tests/cases/compiler/objectLiteralExcessProperties.ts(17,26): error TS2322: Type
|
||||
Object literal may only specify known properties, but 'foreward' does not exist in type 'Book & Cover'. Did you mean to write 'foreword'?
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(19,57): error TS2322: Type '{ foreword: string; color: string; price: number; }' is not assignable to type 'Book & Cover'.
|
||||
Object literal may only specify known properties, and 'price' does not exist in type 'Book & Cover'.
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(21,43): error TS2322: Type '{ foreword: string; price: number; }' is not assignable to type 'Book & number'.
|
||||
Object literal may only specify known properties, and 'price' does not exist in type 'Book & number'.
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(21,5): error TS2322: Type '{ foreword: string; price: number; }' is not assignable to type 'Book & number'.
|
||||
Type '{ foreword: string; price: number; }' is not assignable to type 'number'.
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(23,29): error TS2322: Type '{ couleur: string; }' is not assignable to type 'Cover | Cover[]'.
|
||||
Object literal may only specify known properties, and 'couleur' does not exist in type 'Cover | Cover[]'.
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(25,27): error TS2322: Type '{ forewarned: string; }' is not assignable to type 'Book | Book[]'.
|
||||
Object literal may only specify known properties, and 'forewarned' does not exist in type 'Book | Book[]'.
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(33,27): error TS2322: Type '{ colour: string; }' is not assignable to type 'Cover'.
|
||||
Object literal may only specify known properties, but 'colour' does not exist in type 'Cover'. Did you mean to write 'color'?
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(37,25): error TS2304: Cannot find name 'IFoo'.
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(39,11): error TS2322: Type '{ name: string; }' is not assignable to type 'T'.
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(41,11): error TS2322: Type '{ name: string; prop: boolean; }' is not assignable to type 'T & { prop: boolean; }'.
|
||||
Type '{ name: string; prop: boolean; }' is not assignable to type 'T'.
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(43,43): error TS2322: Type '{ name: string; prop: boolean; }' is not assignable to type 'T | { prop: boolean; }'.
|
||||
Object literal may only specify known properties, and 'name' does not exist in type '{ prop: boolean; }'.
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(45,76): error TS2322: Type '{ name: string; prop: boolean; }' is not assignable to type '{ name: string; } | (T & { prop: boolean; })'.
|
||||
Object literal may only specify known properties, and 'prop' does not exist in type '{ name: string; }'.
|
||||
tests/cases/compiler/objectLiteralExcessProperties.ts(49,44): error TS2322: Type '{ z: string; }' is not assignable to type 'object & { x: string; }'.
|
||||
Object literal may only specify known properties, and 'z' does not exist in type 'object & { x: string; }'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/objectLiteralExcessProperties.ts (10 errors) ====
|
||||
==== tests/cases/compiler/objectLiteralExcessProperties.ts (16 errors) ====
|
||||
interface Book {
|
||||
foreword: string;
|
||||
}
|
||||
@@ -40,7 +50,7 @@ tests/cases/compiler/objectLiteralExcessProperties.ts(33,27): error TS2322: Type
|
||||
var b2: Book | string = { foreward: "nope" };
|
||||
~~~~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type '{ foreward: string; }' is not assignable to type 'string | Book'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'foreward' does not exist in type 'string | Book'.
|
||||
!!! error TS2322: Object literal may only specify known properties, but 'foreward' does not exist in type 'Book'. Did you mean to write 'foreword'?
|
||||
|
||||
var b3: Book | (Book[]) = [{ foreword: "hello" }, { forwards: "back" }];
|
||||
~~~~~~~~~~~~~~~~
|
||||
@@ -66,9 +76,9 @@ tests/cases/compiler/objectLiteralExcessProperties.ts(33,27): error TS2322: Type
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'price' does not exist in type 'Book & Cover'.
|
||||
|
||||
var b7: Book & number = { foreword: "hi", price: 10.99 };
|
||||
~~~~~~~~~~~~
|
||||
~~
|
||||
!!! error TS2322: Type '{ foreword: string; price: number; }' is not assignable to type 'Book & number'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'price' does not exist in type 'Book & number'.
|
||||
!!! error TS2322: Type '{ foreword: string; price: number; }' is not assignable to type 'number'.
|
||||
|
||||
var b8: Cover | Cover[] = { couleur : "non" };
|
||||
~~~~~~~~~~~~~~~
|
||||
@@ -91,4 +101,37 @@ tests/cases/compiler/objectLiteralExcessProperties.ts(33,27): error TS2322: Type
|
||||
!!! error TS2322: Type '{ colour: string; }' is not assignable to type 'Cover'.
|
||||
!!! error TS2322: Object literal may only specify known properties, but 'colour' does not exist in type 'Cover'. Did you mean to write 'color'?
|
||||
!!! related TS6501 tests/cases/compiler/objectLiteralExcessProperties.ts:28:5: The expected type comes from this index signature.
|
||||
|
||||
// Repros inspired by #28752
|
||||
|
||||
function test<T extends IFoo>() {
|
||||
~~~~
|
||||
!!! error TS2304: Cannot find name 'IFoo'.
|
||||
// No excess property checks on generic types
|
||||
const obj1: T = { name: "test" };
|
||||
~~~~
|
||||
!!! error TS2322: Type '{ name: string; }' is not assignable to type 'T'.
|
||||
// No excess property checks on intersections involving generics
|
||||
const obj2: T & { prop: boolean } = { name: "test", prop: true };
|
||||
~~~~
|
||||
!!! error TS2322: Type '{ name: string; prop: boolean; }' is not assignable to type 'T & { prop: boolean; }'.
|
||||
!!! error TS2322: Type '{ name: string; prop: boolean; }' is not assignable to type 'T'.
|
||||
// Excess property checks only on non-generic parts of unions
|
||||
const obj3: T | { prop: boolean } = { name: "test", prop: true };
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2322: Type '{ name: string; prop: boolean; }' is not assignable to type 'T | { prop: boolean; }'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'name' does not exist in type '{ prop: boolean; }'.
|
||||
// Excess property checks only on non-generic parts of unions
|
||||
const obj4: T & { prop: boolean } | { name: string } = { name: "test", prop: true };
|
||||
~~~~~~~~~~
|
||||
!!! error TS2322: Type '{ name: string; prop: boolean; }' is not assignable to type '{ name: string; } | (T & { prop: boolean; })'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'prop' does not exist in type '{ name: string; }'.
|
||||
// No excess property checks when union includes 'object' type
|
||||
const obj5: object | { x: string } = { z: 'abc' }
|
||||
// The 'object' type has no effect on intersections
|
||||
const obj6: object & { x: string } = { z: 'abc' }
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type '{ z: string; }' is not assignable to type 'object & { x: string; }'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'z' does not exist in type 'object & { x: string; }'.
|
||||
}
|
||||
|
||||
@@ -32,6 +32,23 @@ interface Indexed {
|
||||
var b10: Indexed = { 0: { }, '1': { } }; // ok
|
||||
|
||||
var b11: Indexed = { 0: { colour: "blue" } }; // nested object literal still errors
|
||||
|
||||
// Repros inspired by #28752
|
||||
|
||||
function test<T extends IFoo>() {
|
||||
// No excess property checks on generic types
|
||||
const obj1: T = { name: "test" };
|
||||
// No excess property checks on intersections involving generics
|
||||
const obj2: T & { prop: boolean } = { name: "test", prop: true };
|
||||
// Excess property checks only on non-generic parts of unions
|
||||
const obj3: T | { prop: boolean } = { name: "test", prop: true };
|
||||
// Excess property checks only on non-generic parts of unions
|
||||
const obj4: T & { prop: boolean } | { name: string } = { name: "test", prop: true };
|
||||
// No excess property checks when union includes 'object' type
|
||||
const obj5: object | { x: string } = { z: 'abc' }
|
||||
// The 'object' type has no effect on intersections
|
||||
const obj6: object & { x: string } = { z: 'abc' }
|
||||
}
|
||||
|
||||
|
||||
//// [objectLiteralExcessProperties.js]
|
||||
@@ -46,3 +63,18 @@ var b8 = { couleur: "non" };
|
||||
var b9 = { forewarned: "still no" };
|
||||
var b10 = { 0: {}, '1': {} }; // ok
|
||||
var b11 = { 0: { colour: "blue" } }; // nested object literal still errors
|
||||
// Repros inspired by #28752
|
||||
function test() {
|
||||
// No excess property checks on generic types
|
||||
var obj1 = { name: "test" };
|
||||
// No excess property checks on intersections involving generics
|
||||
var obj2 = { name: "test", prop: true };
|
||||
// Excess property checks only on non-generic parts of unions
|
||||
var obj3 = { name: "test", prop: true };
|
||||
// Excess property checks only on non-generic parts of unions
|
||||
var obj4 = { name: "test", prop: true };
|
||||
// No excess property checks when union includes 'object' type
|
||||
var obj5 = { z: 'abc' };
|
||||
// The 'object' type has no effect on intersections
|
||||
var obj6 = { z: 'abc' };
|
||||
}
|
||||
|
||||
@@ -90,3 +90,53 @@ var b11: Indexed = { 0: { colour: "blue" } }; // nested object literal still err
|
||||
>0 : Symbol(0, Decl(objectLiteralExcessProperties.ts, 32, 20))
|
||||
>colour : Symbol(colour, Decl(objectLiteralExcessProperties.ts, 32, 25))
|
||||
|
||||
// Repros inspired by #28752
|
||||
|
||||
function test<T extends IFoo>() {
|
||||
>test : Symbol(test, Decl(objectLiteralExcessProperties.ts, 32, 45))
|
||||
>T : Symbol(T, Decl(objectLiteralExcessProperties.ts, 36, 14))
|
||||
|
||||
// No excess property checks on generic types
|
||||
const obj1: T = { name: "test" };
|
||||
>obj1 : Symbol(obj1, Decl(objectLiteralExcessProperties.ts, 38, 9))
|
||||
>T : Symbol(T, Decl(objectLiteralExcessProperties.ts, 36, 14))
|
||||
>name : Symbol(name, Decl(objectLiteralExcessProperties.ts, 38, 21))
|
||||
|
||||
// No excess property checks on intersections involving generics
|
||||
const obj2: T & { prop: boolean } = { name: "test", prop: true };
|
||||
>obj2 : Symbol(obj2, Decl(objectLiteralExcessProperties.ts, 40, 9))
|
||||
>T : Symbol(T, Decl(objectLiteralExcessProperties.ts, 36, 14))
|
||||
>prop : Symbol(prop, Decl(objectLiteralExcessProperties.ts, 40, 21))
|
||||
>name : Symbol(name, Decl(objectLiteralExcessProperties.ts, 40, 41))
|
||||
>prop : Symbol(prop, Decl(objectLiteralExcessProperties.ts, 40, 55))
|
||||
|
||||
// Excess property checks only on non-generic parts of unions
|
||||
const obj3: T | { prop: boolean } = { name: "test", prop: true };
|
||||
>obj3 : Symbol(obj3, Decl(objectLiteralExcessProperties.ts, 42, 9))
|
||||
>T : Symbol(T, Decl(objectLiteralExcessProperties.ts, 36, 14))
|
||||
>prop : Symbol(prop, Decl(objectLiteralExcessProperties.ts, 42, 21))
|
||||
>name : Symbol(name, Decl(objectLiteralExcessProperties.ts, 42, 41))
|
||||
>prop : Symbol(prop, Decl(objectLiteralExcessProperties.ts, 42, 55))
|
||||
|
||||
// Excess property checks only on non-generic parts of unions
|
||||
const obj4: T & { prop: boolean } | { name: string } = { name: "test", prop: true };
|
||||
>obj4 : Symbol(obj4, Decl(objectLiteralExcessProperties.ts, 44, 9))
|
||||
>T : Symbol(T, Decl(objectLiteralExcessProperties.ts, 36, 14))
|
||||
>prop : Symbol(prop, Decl(objectLiteralExcessProperties.ts, 44, 21))
|
||||
>name : Symbol(name, Decl(objectLiteralExcessProperties.ts, 44, 41))
|
||||
>name : Symbol(name, Decl(objectLiteralExcessProperties.ts, 44, 60))
|
||||
>prop : Symbol(prop, Decl(objectLiteralExcessProperties.ts, 44, 74))
|
||||
|
||||
// No excess property checks when union includes 'object' type
|
||||
const obj5: object | { x: string } = { z: 'abc' }
|
||||
>obj5 : Symbol(obj5, Decl(objectLiteralExcessProperties.ts, 46, 9))
|
||||
>x : Symbol(x, Decl(objectLiteralExcessProperties.ts, 46, 26))
|
||||
>z : Symbol(z, Decl(objectLiteralExcessProperties.ts, 46, 42))
|
||||
|
||||
// The 'object' type has no effect on intersections
|
||||
const obj6: object & { x: string } = { z: 'abc' }
|
||||
>obj6 : Symbol(obj6, Decl(objectLiteralExcessProperties.ts, 48, 9))
|
||||
>x : Symbol(x, Decl(objectLiteralExcessProperties.ts, 48, 26))
|
||||
>z : Symbol(z, Decl(objectLiteralExcessProperties.ts, 48, 42))
|
||||
}
|
||||
|
||||
|
||||
@@ -98,3 +98,63 @@ var b11: Indexed = { 0: { colour: "blue" } }; // nested object literal still err
|
||||
>colour : string
|
||||
>"blue" : "blue"
|
||||
|
||||
// Repros inspired by #28752
|
||||
|
||||
function test<T extends IFoo>() {
|
||||
>test : <T extends any>() => void
|
||||
|
||||
// No excess property checks on generic types
|
||||
const obj1: T = { name: "test" };
|
||||
>obj1 : T
|
||||
>{ name: "test" } : { name: string; }
|
||||
>name : string
|
||||
>"test" : "test"
|
||||
|
||||
// No excess property checks on intersections involving generics
|
||||
const obj2: T & { prop: boolean } = { name: "test", prop: true };
|
||||
>obj2 : T & { prop: boolean; }
|
||||
>prop : boolean
|
||||
>{ name: "test", prop: true } : { name: string; prop: boolean; }
|
||||
>name : string
|
||||
>"test" : "test"
|
||||
>prop : boolean
|
||||
>true : true
|
||||
|
||||
// Excess property checks only on non-generic parts of unions
|
||||
const obj3: T | { prop: boolean } = { name: "test", prop: true };
|
||||
>obj3 : T | { prop: boolean; }
|
||||
>prop : boolean
|
||||
>{ name: "test", prop: true } : { name: string; prop: boolean; }
|
||||
>name : string
|
||||
>"test" : "test"
|
||||
>prop : boolean
|
||||
>true : true
|
||||
|
||||
// Excess property checks only on non-generic parts of unions
|
||||
const obj4: T & { prop: boolean } | { name: string } = { name: "test", prop: true };
|
||||
>obj4 : { name: string; } | (T & { prop: boolean; })
|
||||
>prop : boolean
|
||||
>name : string
|
||||
>{ name: "test", prop: true } : { name: string; prop: boolean; }
|
||||
>name : string
|
||||
>"test" : "test"
|
||||
>prop : boolean
|
||||
>true : true
|
||||
|
||||
// No excess property checks when union includes 'object' type
|
||||
const obj5: object | { x: string } = { z: 'abc' }
|
||||
>obj5 : object | { x: string; }
|
||||
>x : string
|
||||
>{ z: 'abc' } : { z: string; }
|
||||
>z : string
|
||||
>'abc' : "abc"
|
||||
|
||||
// The 'object' type has no effect on intersections
|
||||
const obj6: object & { x: string } = { z: 'abc' }
|
||||
>obj6 : object & { x: string; }
|
||||
>x : string
|
||||
>{ z: 'abc' } : { z: string; }
|
||||
>z : string
|
||||
>'abc' : "abc"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
tests/cases/conformance/jsx/tsxIntrinsicAttributeErrors.tsx(29,2): error TS2322: Type '{ x: number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<{ x: number; render(): void; }> & string'.
|
||||
Property 'x' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<{ x: number; render(): void; }> & string'.
|
||||
tests/cases/conformance/jsx/tsxIntrinsicAttributeErrors.tsx(29,2): error TS2741: Property 'key' is missing in type '{ x: number; }' but required in type 'IntrinsicAttributes'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/tsxIntrinsicAttributeErrors.tsx (1 errors) ====
|
||||
@@ -33,6 +32,6 @@ tests/cases/conformance/jsx/tsxIntrinsicAttributeErrors.tsx(29,2): error TS2322:
|
||||
var E: I;
|
||||
<E x={10} />
|
||||
~
|
||||
!!! error TS2322: Type '{ x: number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<{ x: number; render(): void; }> & string'.
|
||||
!!! error TS2322: Property 'x' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<{ x: number; render(): void; }> & string'.
|
||||
!!! error TS2741: Property 'key' is missing in type '{ x: number; }' but required in type 'IntrinsicAttributes'.
|
||||
!!! related TS2728 tests/cases/conformance/jsx/tsxIntrinsicAttributeErrors.tsx:7:9: 'key' is declared here.
|
||||
|
||||
@@ -31,3 +31,20 @@ interface Indexed {
|
||||
var b10: Indexed = { 0: { }, '1': { } }; // ok
|
||||
|
||||
var b11: Indexed = { 0: { colour: "blue" } }; // nested object literal still errors
|
||||
|
||||
// Repros inspired by #28752
|
||||
|
||||
function test<T extends IFoo>() {
|
||||
// No excess property checks on generic types
|
||||
const obj1: T = { name: "test" };
|
||||
// No excess property checks on intersections involving generics
|
||||
const obj2: T & { prop: boolean } = { name: "test", prop: true };
|
||||
// Excess property checks only on non-generic parts of unions
|
||||
const obj3: T | { prop: boolean } = { name: "test", prop: true };
|
||||
// Excess property checks only on non-generic parts of unions
|
||||
const obj4: T & { prop: boolean } | { name: string } = { name: "test", prop: true };
|
||||
// No excess property checks when union includes 'object' type
|
||||
const obj5: object | { x: string } = { z: 'abc' }
|
||||
// The 'object' type has no effect on intersections
|
||||
const obj6: object & { x: string } = { z: 'abc' }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user