diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3e82389e269d2..2506e4632d893 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22585,15 +22585,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (match === -1) { return defaultValue; } - // make sure exactly 1 matches before returning it - let nextMatch = discriminable.indexOf(/*searchElement*/ true, match + 1); - while (nextMatch !== -1) { - if (!isTypeIdenticalTo(target.types[match], target.types[nextMatch])) { - return defaultValue; - } - nextMatch = discriminable.indexOf(/*searchElement*/ true, nextMatch + 1); - } - return target.types[match]; + return getUnionType(target.types.filter((_, index) => discriminable[index])); } /** diff --git a/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.errors.txt b/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.errors.txt index 00e0e3dc8d10f..62f17936146a4 100644 --- a/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.errors.txt +++ b/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.errors.txt @@ -2,11 +2,19 @@ tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(30,5): erro Object literal may only specify known properties, and 'multipleOf' does not exist in type 'Float'. tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(41,5): error TS2322: Type '{ p1: "left"; p2: false; p3: number; p4: string; }' is not assignable to type 'DisjointDiscriminants'. Object literal may only specify known properties, and 'p3' does not exist in type '{ p1: "left"; p2: boolean; }'. +tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(50,5): error TS2322: Type '{ p1: "left"; p2: true; p3: number; p4: string; }' is not assignable to type 'DisjointDiscriminants'. + Object literal may only specify known properties, and 'p4' does not exist in type '{ p1: "left"; p2: true; p3: number; } | { p1: "left"; p2: boolean; }'. tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(57,5): error TS2322: Type '{ p1: "right"; p2: false; p3: number; p4: string; }' is not assignable to type 'DisjointDiscriminants'. Object literal may only specify known properties, and 'p3' does not exist in type '{ p1: "right"; p2: false; p4: string; }'. +tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(83,5): error TS2322: Type '{ type: "A"; n: number; a: number; b: number; }' is not assignable to type 'CommonWithOverlappingOptionals'. + Object literal may only specify known properties, and 'b' does not exist in type 'Common | (Common & A)'. +tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(93,5): error TS2322: Type '{ type: "A"; n: number; a: number; b: number; }' is not assignable to type 'CommonWithDisjointOverlappingOptionals'. + Object literal may only specify known properties, and 'b' does not exist in type 'Common | A'. +tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(130,5): error TS2322: Type '"string"' is not assignable to type '"number"'. +tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(136,5): error TS2322: Type '"string"' is not assignable to type '"number"'. -==== tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts (3 errors) ==== +==== tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts (8 errors) ==== // Repro from #32657 interface Base { @@ -57,12 +65,15 @@ tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(57,5): erro p4: "hello" }; - // This has no excess error because variant one and three are both applicable. + // This has excess error because variant two is not applicable. const b: DisjointDiscriminants = { p1: 'left', p2: true, p3: 42, p4: "hello" + ~~ +!!! error TS2322: Type '{ p1: "left"; p2: true; p3: number; p4: string; }' is not assignable to type 'DisjointDiscriminants'. +!!! error TS2322: Object literal may only specify known properties, and 'p4' does not exist in type '{ p1: "left"; p2: true; p3: number; } | { p1: "left"; p2: boolean; }'. }; // This has excess error because variant two is the only applicable case @@ -75,4 +86,94 @@ tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(57,5): erro !!! error TS2322: Object literal may only specify known properties, and 'p3' does not exist in type '{ p1: "right"; p2: false; p4: string; }'. p4: "hello" }; + + // Repro from #51873 + + interface Common { + type: "A" | "B" | "C" | "D"; + n: number; + } + interface A { + type: "A"; + a?: number; + } + interface B { + type: "B"; + b?: number; + } + + type CommonWithOverlappingOptionals = Common | (Common & A) | (Common & B); + + // Should reject { b } because reduced to Common | (Common & A) + const c1: CommonWithOverlappingOptionals = { + type: "A", + n: 1, + a: 1, + b: 1 // excess property + ~ +!!! error TS2322: Type '{ type: "A"; n: number; a: number; b: number; }' is not assignable to type 'CommonWithOverlappingOptionals'. +!!! error TS2322: Object literal may only specify known properties, and 'b' does not exist in type 'Common | (Common & A)'. + } + + type CommonWithDisjointOverlappingOptionals = Common | A | B; + + // Should still reject { b } because reduced to Common | A, even though these are now disjoint + const c2: CommonWithDisjointOverlappingOptionals = { + type: "A", + n: 1, + a: 1, + b: 1 // excess property + ~ +!!! error TS2322: Type '{ type: "A"; n: number; a: number; b: number; }' is not assignable to type 'CommonWithDisjointOverlappingOptionals'. +!!! error TS2322: Object literal may only specify known properties, and 'b' does not exist in type 'Common | A'. + } + + // Repro from https://github.com/microsoft/TypeScript/pull/51884#issuecomment-1472736068 + + export type BaseAttribute = { + type?: string | undefined; + required?: boolean | undefined; + defaultsTo?: T | undefined; + }; + + export type Attribute = + | string + | StringAttribute + | NumberAttribute + | OneToOneAttribute + + export type Attribute2 = + | string + | StringAttribute + | NumberAttribute + + export type StringAttribute = BaseAttribute & { + type: 'string'; + }; + + export type NumberAttribute = BaseAttribute & { + type: 'number'; + autoIncrement?: boolean | undefined; + }; + + export type OneToOneAttribute = BaseAttribute & { + model: string; + }; + + // both should error due to excess properties + const attributes: Attribute = { + type: 'string', + ~~~~ +!!! error TS2322: Type '"string"' is not assignable to type '"number"'. + autoIncrement: true, + required: true, + }; + + const attributes2: Attribute2 = { + type: 'string', + ~~~~ +!!! error TS2322: Type '"string"' is not assignable to type '"number"'. + autoIncrement: true, + required: true, + }; \ No newline at end of file diff --git a/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.js b/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.js index a847e63aa5a1f..39414112f6d16 100644 --- a/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.js +++ b/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.js @@ -43,7 +43,7 @@ const a: DisjointDiscriminants = { p4: "hello" }; -// This has no excess error because variant one and three are both applicable. +// This has excess error because variant two is not applicable. const b: DisjointDiscriminants = { p1: 'left', p2: true, @@ -58,10 +58,92 @@ const c: DisjointDiscriminants = { p3: 42, p4: "hello" }; + +// Repro from #51873 + +interface Common { + type: "A" | "B" | "C" | "D"; + n: number; +} +interface A { + type: "A"; + a?: number; +} +interface B { + type: "B"; + b?: number; +} + +type CommonWithOverlappingOptionals = Common | (Common & A) | (Common & B); + +// Should reject { b } because reduced to Common | (Common & A) +const c1: CommonWithOverlappingOptionals = { + type: "A", + n: 1, + a: 1, + b: 1 // excess property +} + +type CommonWithDisjointOverlappingOptionals = Common | A | B; + +// Should still reject { b } because reduced to Common | A, even though these are now disjoint +const c2: CommonWithDisjointOverlappingOptionals = { + type: "A", + n: 1, + a: 1, + b: 1 // excess property +} + +// Repro from https://github.com/microsoft/TypeScript/pull/51884#issuecomment-1472736068 + +export type BaseAttribute = { + type?: string | undefined; + required?: boolean | undefined; + defaultsTo?: T | undefined; +}; + +export type Attribute = + | string + | StringAttribute + | NumberAttribute + | OneToOneAttribute + +export type Attribute2 = + | string + | StringAttribute + | NumberAttribute + +export type StringAttribute = BaseAttribute & { + type: 'string'; +}; + +export type NumberAttribute = BaseAttribute & { + type: 'number'; + autoIncrement?: boolean | undefined; +}; + +export type OneToOneAttribute = BaseAttribute & { + model: string; +}; + +// both should error due to excess properties +const attributes: Attribute = { + type: 'string', + autoIncrement: true, + required: true, +}; + +const attributes2: Attribute2 = { + type: 'string', + autoIncrement: true, + required: true, +}; //// [excessPropertyCheckWithMultipleDiscriminants.js] +"use strict"; // Repro from #32657 +Object.defineProperty(exports, "__esModule", { value: true }); var foo = { type: "number", value: 10, @@ -75,7 +157,7 @@ var a = { p3: 42, p4: "hello" }; -// This has no excess error because variant one and three are both applicable. +// This has excess error because variant two is not applicable. var b = { p1: 'left', p2: true, @@ -89,3 +171,28 @@ var c = { p3: 42, p4: "hello" }; +// Should reject { b } because reduced to Common | (Common & A) +var c1 = { + type: "A", + n: 1, + a: 1, + b: 1 // excess property +}; +// Should still reject { b } because reduced to Common | A, even though these are now disjoint +var c2 = { + type: "A", + n: 1, + a: 1, + b: 1 // excess property +}; +// both should error due to excess properties +var attributes = { + type: 'string', + autoIncrement: true, + required: true, +}; +var attributes2 = { + type: 'string', + autoIncrement: true, + required: true, +}; diff --git a/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.symbols b/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.symbols index 7a1b06b045a74..187c2b852c90c 100644 --- a/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.symbols +++ b/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.symbols @@ -103,7 +103,7 @@ const a: DisjointDiscriminants = { }; -// This has no excess error because variant one and three are both applicable. +// This has excess error because variant two is not applicable. const b: DisjointDiscriminants = { >b : Symbol(b, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 45, 5)) >DisjointDiscriminants : Symbol(DisjointDiscriminants, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 31, 1)) @@ -141,3 +141,185 @@ const c: DisjointDiscriminants = { }; +// Repro from #51873 + +interface Common { +>Common : Symbol(Common, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 58, 2)) + + type: "A" | "B" | "C" | "D"; +>type : Symbol(Common.type, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 62, 18)) + + n: number; +>n : Symbol(Common.n, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 63, 32)) +} +interface A { +>A : Symbol(A, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 65, 1)) + + type: "A"; +>type : Symbol(A.type, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 66, 13)) + + a?: number; +>a : Symbol(A.a, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 67, 14)) +} +interface B { +>B : Symbol(B, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 69, 1)) + + type: "B"; +>type : Symbol(B.type, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 70, 13)) + + b?: number; +>b : Symbol(B.b, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 71, 14)) +} + +type CommonWithOverlappingOptionals = Common | (Common & A) | (Common & B); +>CommonWithOverlappingOptionals : Symbol(CommonWithOverlappingOptionals, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 73, 1)) +>Common : Symbol(Common, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 58, 2)) +>Common : Symbol(Common, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 58, 2)) +>A : Symbol(A, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 65, 1)) +>Common : Symbol(Common, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 58, 2)) +>B : Symbol(B, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 69, 1)) + +// Should reject { b } because reduced to Common | (Common & A) +const c1: CommonWithOverlappingOptionals = { +>c1 : Symbol(c1, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 78, 5)) +>CommonWithOverlappingOptionals : Symbol(CommonWithOverlappingOptionals, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 73, 1)) + + type: "A", +>type : Symbol(type, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 78, 44)) + + n: 1, +>n : Symbol(n, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 79, 14)) + + a: 1, +>a : Symbol(a, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 80, 9)) + + b: 1 // excess property +>b : Symbol(b, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 81, 9)) +} + +type CommonWithDisjointOverlappingOptionals = Common | A | B; +>CommonWithDisjointOverlappingOptionals : Symbol(CommonWithDisjointOverlappingOptionals, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 83, 1)) +>Common : Symbol(Common, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 58, 2)) +>A : Symbol(A, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 65, 1)) +>B : Symbol(B, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 69, 1)) + +// Should still reject { b } because reduced to Common | A, even though these are now disjoint +const c2: CommonWithDisjointOverlappingOptionals = { +>c2 : Symbol(c2, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 88, 5)) +>CommonWithDisjointOverlappingOptionals : Symbol(CommonWithDisjointOverlappingOptionals, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 83, 1)) + + type: "A", +>type : Symbol(type, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 88, 52)) + + n: 1, +>n : Symbol(n, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 89, 14)) + + a: 1, +>a : Symbol(a, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 90, 9)) + + b: 1 // excess property +>b : Symbol(b, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 91, 9)) +} + +// Repro from https://github.com/microsoft/TypeScript/pull/51884#issuecomment-1472736068 + +export type BaseAttribute = { +>BaseAttribute : Symbol(BaseAttribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 93, 1)) +>T : Symbol(T, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 97, 26)) + + type?: string | undefined; +>type : Symbol(type, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 97, 32)) + + required?: boolean | undefined; +>required : Symbol(required, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 98, 30)) + + defaultsTo?: T | undefined; +>defaultsTo : Symbol(defaultsTo, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 99, 35)) +>T : Symbol(T, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 97, 26)) + +}; + +export type Attribute = +>Attribute : Symbol(Attribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 101, 2)) + + | string + | StringAttribute +>StringAttribute : Symbol(StringAttribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 112, 21)) + + | NumberAttribute +>NumberAttribute : Symbol(NumberAttribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 116, 2)) + + | OneToOneAttribute +>OneToOneAttribute : Symbol(OneToOneAttribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 121, 2)) + +export type Attribute2 = +>Attribute2 : Symbol(Attribute2, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 107, 23)) + + | string + | StringAttribute +>StringAttribute : Symbol(StringAttribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 112, 21)) + + | NumberAttribute +>NumberAttribute : Symbol(NumberAttribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 116, 2)) + +export type StringAttribute = BaseAttribute & { +>StringAttribute : Symbol(StringAttribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 112, 21)) +>BaseAttribute : Symbol(BaseAttribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 93, 1)) + + type: 'string'; +>type : Symbol(type, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 114, 55)) + +}; + +export type NumberAttribute = BaseAttribute & { +>NumberAttribute : Symbol(NumberAttribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 116, 2)) +>BaseAttribute : Symbol(BaseAttribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 93, 1)) + + type: 'number'; +>type : Symbol(type, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 118, 55)) + + autoIncrement?: boolean | undefined; +>autoIncrement : Symbol(autoIncrement, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 119, 19)) + +}; + +export type OneToOneAttribute = BaseAttribute & { +>OneToOneAttribute : Symbol(OneToOneAttribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 121, 2)) +>BaseAttribute : Symbol(BaseAttribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 93, 1)) + + model: string; +>model : Symbol(model, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 123, 54)) + +}; + +// both should error due to excess properties +const attributes: Attribute = { +>attributes : Symbol(attributes, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 128, 5)) +>Attribute : Symbol(Attribute, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 101, 2)) + + type: 'string', +>type : Symbol(type, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 128, 31)) + + autoIncrement: true, +>autoIncrement : Symbol(autoIncrement, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 129, 19)) + + required: true, +>required : Symbol(required, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 130, 24)) + +}; + +const attributes2: Attribute2 = { +>attributes2 : Symbol(attributes2, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 134, 5)) +>Attribute2 : Symbol(Attribute2, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 107, 23)) + + type: 'string', +>type : Symbol(type, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 134, 33)) + + autoIncrement: true, +>autoIncrement : Symbol(autoIncrement, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 135, 19)) + + required: true, +>required : Symbol(required, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 136, 24)) + +}; + diff --git a/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.types b/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.types index 2c5b07e591444..b2f6e5a7b31b9 100644 --- a/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.types +++ b/tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.types @@ -93,7 +93,7 @@ const a: DisjointDiscriminants = { }; -// This has no excess error because variant one and three are both applicable. +// This has excess error because variant two is not applicable. const b: DisjointDiscriminants = { >b : DisjointDiscriminants >{ p1: 'left', p2: true, p3: 42, p4: "hello"} : { p1: "left"; p2: true; p3: number; p4: string; } @@ -139,3 +139,172 @@ const c: DisjointDiscriminants = { }; +// Repro from #51873 + +interface Common { + type: "A" | "B" | "C" | "D"; +>type : "A" | "B" | "C" | "D" + + n: number; +>n : number +} +interface A { + type: "A"; +>type : "A" + + a?: number; +>a : number +} +interface B { + type: "B"; +>type : "B" + + b?: number; +>b : number +} + +type CommonWithOverlappingOptionals = Common | (Common & A) | (Common & B); +>CommonWithOverlappingOptionals : Common | (Common & A) | (Common & B) + +// Should reject { b } because reduced to Common | (Common & A) +const c1: CommonWithOverlappingOptionals = { +>c1 : CommonWithOverlappingOptionals +>{ type: "A", n: 1, a: 1, b: 1 // excess property} : { type: "A"; n: number; a: number; b: number; } + + type: "A", +>type : "A" +>"A" : "A" + + n: 1, +>n : number +>1 : 1 + + a: 1, +>a : number +>1 : 1 + + b: 1 // excess property +>b : number +>1 : 1 +} + +type CommonWithDisjointOverlappingOptionals = Common | A | B; +>CommonWithDisjointOverlappingOptionals : Common | A | B + +// Should still reject { b } because reduced to Common | A, even though these are now disjoint +const c2: CommonWithDisjointOverlappingOptionals = { +>c2 : CommonWithDisjointOverlappingOptionals +>{ type: "A", n: 1, a: 1, b: 1 // excess property} : { type: "A"; n: number; a: number; b: number; } + + type: "A", +>type : "A" +>"A" : "A" + + n: 1, +>n : number +>1 : 1 + + a: 1, +>a : number +>1 : 1 + + b: 1 // excess property +>b : number +>1 : 1 +} + +// Repro from https://github.com/microsoft/TypeScript/pull/51884#issuecomment-1472736068 + +export type BaseAttribute = { +>BaseAttribute : BaseAttribute + + type?: string | undefined; +>type : string + + required?: boolean | undefined; +>required : boolean + + defaultsTo?: T | undefined; +>defaultsTo : T + +}; + +export type Attribute = +>Attribute : string | StringAttribute | NumberAttribute | OneToOneAttribute + + | string + | StringAttribute + | NumberAttribute + | OneToOneAttribute + +export type Attribute2 = +>Attribute2 : string | StringAttribute | NumberAttribute + + | string + | StringAttribute + | NumberAttribute + +export type StringAttribute = BaseAttribute & { +>StringAttribute : BaseAttribute & { type: 'string'; } + + type: 'string'; +>type : "string" + +}; + +export type NumberAttribute = BaseAttribute & { +>NumberAttribute : BaseAttribute & { type: 'number'; autoIncrement?: boolean | undefined; } + + type: 'number'; +>type : "number" + + autoIncrement?: boolean | undefined; +>autoIncrement : boolean + +}; + +export type OneToOneAttribute = BaseAttribute & { +>OneToOneAttribute : BaseAttribute & { model: string; } + + model: string; +>model : string + +}; + +// both should error due to excess properties +const attributes: Attribute = { +>attributes : Attribute +>{ type: 'string', autoIncrement: true, required: true,} : { type: "string"; autoIncrement: boolean; required: true; } + + type: 'string', +>type : "string" +>'string' : "string" + + autoIncrement: true, +>autoIncrement : boolean +>true : true + + required: true, +>required : true +>true : true + +}; + +const attributes2: Attribute2 = { +>attributes2 : Attribute2 +>{ type: 'string', autoIncrement: true, required: true,} : { type: "string"; autoIncrement: boolean; required: true; } + + type: 'string', +>type : "string" +>'string' : "string" + + autoIncrement: true, +>autoIncrement : boolean +>true : true + + required: true, +>required : true +>true : true + +}; + diff --git a/tests/baselines/reference/excessPropertyCheckWithUnions.errors.txt b/tests/baselines/reference/excessPropertyCheckWithUnions.errors.txt index dc6484b7a9195..247aa349ebdfa 100644 --- a/tests/baselines/reference/excessPropertyCheckWithUnions.errors.txt +++ b/tests/baselines/reference/excessPropertyCheckWithUnions.errors.txt @@ -5,30 +5,27 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(11,21): error TS2322: Type tests/cases/compiler/excessPropertyCheckWithUnions.ts(12,1): error TS2322: Type '{ tag: "D"; }' is not assignable to type 'ADT'. Property 'd20' is missing in type '{ tag: "D"; }' but required in type '{ tag: "D"; d20: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20; }'. tests/cases/compiler/excessPropertyCheckWithUnions.ts(33,28): error TS2322: Type '{ tag: "A"; x: string; extra: number; }' is not assignable to type 'Ambiguous'. - Object literal may only specify known properties, and 'extra' does not exist in type 'Ambiguous'. + Object literal may only specify known properties, and 'extra' does not exist in type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'. tests/cases/compiler/excessPropertyCheckWithUnions.ts(34,26): error TS2322: Type '{ tag: "A"; y: number; extra: number; }' is not assignable to type 'Ambiguous'. - Object literal may only specify known properties, and 'extra' does not exist in type 'Ambiguous'. -tests/cases/compiler/excessPropertyCheckWithUnions.ts(39,1): error TS2322: Type '{ tag: "A"; }' is not assignable to type 'Ambiguous'. - Type '{ tag: "A"; }' is not assignable to type '{ tag: "C"; }'. - Types of property 'tag' are incompatible. - Type '"A"' is not assignable to type '"C"'. -tests/cases/compiler/excessPropertyCheckWithUnions.ts(40,1): error TS2322: Type '{ tag: "A"; z: true; }' is not assignable to type 'Ambiguous'. - Type '{ tag: "A"; z: true; }' is not assignable to type '{ tag: "B"; z: boolean; }'. - Types of property 'tag' are incompatible. - Type '"A"' is not assignable to type '"B"'. -tests/cases/compiler/excessPropertyCheckWithUnions.ts(49,35): error TS2322: Type '{ a: 1; b: 1; first: string; second: string; }' is not assignable to type 'Overlapping'. + Object literal may only specify known properties, and 'extra' does not exist in type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(37,1): error TS2322: Type '{ tag: "A"; }' is not assignable to type 'Ambiguous'. + Type '{ tag: "A"; }' is not assignable to type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'. + Property 'y' is missing in type '{ tag: "A"; }' but required in type '{ tag: "A"; y: number; }'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(38,19): error TS2322: Type '{ tag: "A"; z: boolean; }' is not assignable to type 'Ambiguous'. + Object literal may only specify known properties, and 'z' does not exist in type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(47,35): error TS2322: Type '{ a: 1; b: 1; first: string; second: string; }' is not assignable to type 'Overlapping'. 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'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(48,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 TS2322: Type '{ kind: "A"; n: { a: string; b: string; }; }' is not assignable to type 'AB'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(64,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'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(85,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(108,5): error TS2322: Type 'string' is not assignable to type 'IValue'. -tests/cases/compiler/excessPropertyCheckWithUnions.ts(113,67): error TS2322: Type 'string' is not assignable to type 'number'. -tests/cases/compiler/excessPropertyCheckWithUnions.ts(114,63): error TS2322: Type 'string' is not assignable to type 'number'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(106,5): error TS2322: Type 'string' is not assignable to type 'IValue'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(111,67): error TS2322: Type 'string' is not assignable to type 'number'. +tests/cases/compiler/excessPropertyCheckWithUnions.ts(112,63): error TS2322: Type 'string' is not assignable to type 'number'. ==== tests/cases/compiler/excessPropertyCheckWithUnions.ts (14 errors) ==== @@ -77,27 +74,23 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(114,63): error TS2322: Typ amb = { tag: "A", x: "hi", extra: 12 } ~~~~~ !!! error TS2322: Type '{ tag: "A"; x: string; extra: number; }' is not assignable to type 'Ambiguous'. -!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type 'Ambiguous'. +!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'. amb = { tag: "A", y: 12, extra: 12 } ~~~~~ !!! error TS2322: Type '{ tag: "A"; y: number; extra: number; }' is not assignable to type 'Ambiguous'. -!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type 'Ambiguous'. +!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'. - // assignability errors still work. - // But note that the error for `z: true` is the fallback one of reporting on - // the last constituent since assignability error reporting can't find a single best discriminant either. + // assignability errors still work amb = { tag: "A" } ~~~ !!! error TS2322: Type '{ tag: "A"; }' is not assignable to type 'Ambiguous'. -!!! error TS2322: Type '{ tag: "A"; }' is not assignable to type '{ tag: "C"; }'. -!!! error TS2322: Types of property 'tag' are incompatible. -!!! error TS2322: Type '"A"' is not assignable to type '"C"'. +!!! error TS2322: Type '{ tag: "A"; }' is not assignable to type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'. +!!! error TS2322: Property 'y' is missing in type '{ tag: "A"; }' but required in type '{ tag: "A"; y: number; }'. +!!! related TS2728 tests/cases/compiler/excessPropertyCheckWithUnions.ts:19:5: 'y' is declared here. amb = { tag: "A", z: true } - ~~~ -!!! error TS2322: Type '{ tag: "A"; z: true; }' is not assignable to type 'Ambiguous'. -!!! error TS2322: Type '{ tag: "A"; z: true; }' is not assignable to type '{ tag: "B"; z: boolean; }'. -!!! error TS2322: Types of property 'tag' are incompatible. -!!! error TS2322: Type '"A"' is not assignable to type '"B"'. + ~ +!!! error TS2322: Type '{ tag: "A"; z: boolean; }' is not assignable to type 'Ambiguous'. +!!! error TS2322: Object literal may only specify known properties, and 'z' does not exist in type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'. type Overlapping = | { a: 1, b: 1, first: string } @@ -167,7 +160,7 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(114,63): error TS2322: Typ value: string } - interface StringKeys { + interface StringKeys { [propertyName: string]: IValue; }; diff --git a/tests/baselines/reference/excessPropertyCheckWithUnions.js b/tests/baselines/reference/excessPropertyCheckWithUnions.js index dabcd824f3693..40be4c89c175e 100644 --- a/tests/baselines/reference/excessPropertyCheckWithUnions.js +++ b/tests/baselines/reference/excessPropertyCheckWithUnions.js @@ -34,9 +34,7 @@ amb = { tag: "A", x: "hi", y: 12 } amb = { tag: "A", x: "hi", extra: 12 } amb = { tag: "A", y: 12, extra: 12 } -// assignability errors still work. -// But note that the error for `z: true` is the fallback one of reporting on -// the last constituent since assignability error reporting can't find a single best discriminant either. +// assignability errors still work amb = { tag: "A" } amb = { tag: "A", z: true } @@ -94,7 +92,7 @@ interface IValue { value: string } -interface StringKeys { +interface StringKeys { [propertyName: string]: IValue; }; @@ -178,9 +176,7 @@ amb = { tag: "A", x: "hi", y: 12 }; // correctly error on excess property 'extra', even when ambiguous amb = { tag: "A", x: "hi", extra: 12 }; amb = { tag: "A", y: 12, extra: 12 }; -// assignability errors still work. -// But note that the error for `z: true` is the fallback one of reporting on -// the last constituent since assignability error reporting can't find a single best discriminant either. +// assignability errors still work amb = { tag: "A" }; amb = { tag: "A", z: true }; var over; diff --git a/tests/baselines/reference/excessPropertyCheckWithUnions.symbols b/tests/baselines/reference/excessPropertyCheckWithUnions.symbols index 80921fedad26c..65cec78a47b5a 100644 --- a/tests/baselines/reference/excessPropertyCheckWithUnions.symbols +++ b/tests/baselines/reference/excessPropertyCheckWithUnions.symbols @@ -95,301 +95,299 @@ amb = { tag: "A", y: 12, extra: 12 } >y : Symbol(y, Decl(excessPropertyCheckWithUnions.ts, 33, 17)) >extra : Symbol(extra, Decl(excessPropertyCheckWithUnions.ts, 33, 24)) -// assignability errors still work. -// But note that the error for `z: true` is the fallback one of reporting on -// the last constituent since assignability error reporting can't find a single best discriminant either. +// assignability errors still work amb = { tag: "A" } >amb : Symbol(amb, Decl(excessPropertyCheckWithUnions.ts, 25, 3)) ->tag : Symbol(tag, Decl(excessPropertyCheckWithUnions.ts, 38, 7)) +>tag : Symbol(tag, Decl(excessPropertyCheckWithUnions.ts, 36, 7)) amb = { tag: "A", z: true } >amb : Symbol(amb, Decl(excessPropertyCheckWithUnions.ts, 25, 3)) ->tag : Symbol(tag, Decl(excessPropertyCheckWithUnions.ts, 39, 7)) ->z : Symbol(z, Decl(excessPropertyCheckWithUnions.ts, 39, 17)) +>tag : Symbol(tag, Decl(excessPropertyCheckWithUnions.ts, 37, 7)) +>z : Symbol(z, Decl(excessPropertyCheckWithUnions.ts, 37, 17)) type Overlapping = ->Overlapping : Symbol(Overlapping, Decl(excessPropertyCheckWithUnions.ts, 39, 27)) +>Overlapping : Symbol(Overlapping, Decl(excessPropertyCheckWithUnions.ts, 37, 27)) | { a: 1, b: 1, first: string } ->a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 42, 7)) ->b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 42, 13)) ->first : Symbol(first, Decl(excessPropertyCheckWithUnions.ts, 42, 19)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 40, 7)) +>b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 40, 13)) +>first : Symbol(first, Decl(excessPropertyCheckWithUnions.ts, 40, 19)) | { a: 2, second: string } ->a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 43, 7)) ->second : Symbol(second, Decl(excessPropertyCheckWithUnions.ts, 43, 13)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 41, 7)) +>second : Symbol(second, Decl(excessPropertyCheckWithUnions.ts, 41, 13)) | { b: 3, third: string } ->b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 44, 7)) ->third : Symbol(third, Decl(excessPropertyCheckWithUnions.ts, 44, 13)) +>b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 42, 7)) +>third : Symbol(third, Decl(excessPropertyCheckWithUnions.ts, 42, 13)) let over: Overlapping ->over : Symbol(over, Decl(excessPropertyCheckWithUnions.ts, 45, 3)) ->Overlapping : Symbol(Overlapping, Decl(excessPropertyCheckWithUnions.ts, 39, 27)) +>over : Symbol(over, Decl(excessPropertyCheckWithUnions.ts, 43, 3)) +>Overlapping : Symbol(Overlapping, Decl(excessPropertyCheckWithUnions.ts, 37, 27)) // these two are still errors despite their doubled up discriminants over = { a: 1, b: 1, first: "ok", second: "error" } ->over : Symbol(over, Decl(excessPropertyCheckWithUnions.ts, 45, 3)) ->a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 48, 8)) ->b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 48, 14)) ->first : Symbol(first, Decl(excessPropertyCheckWithUnions.ts, 48, 20)) ->second : Symbol(second, Decl(excessPropertyCheckWithUnions.ts, 48, 33)) +>over : Symbol(over, Decl(excessPropertyCheckWithUnions.ts, 43, 3)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 46, 8)) +>b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 46, 14)) +>first : Symbol(first, Decl(excessPropertyCheckWithUnions.ts, 46, 20)) +>second : Symbol(second, Decl(excessPropertyCheckWithUnions.ts, 46, 33)) over = { a: 1, b: 1, first: "ok", third: "error" } ->over : Symbol(over, Decl(excessPropertyCheckWithUnions.ts, 45, 3)) ->a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 49, 8)) ->b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 49, 14)) ->first : Symbol(first, Decl(excessPropertyCheckWithUnions.ts, 49, 20)) ->third : Symbol(third, Decl(excessPropertyCheckWithUnions.ts, 49, 33)) +>over : Symbol(over, Decl(excessPropertyCheckWithUnions.ts, 43, 3)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 47, 8)) +>b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 47, 14)) +>first : Symbol(first, Decl(excessPropertyCheckWithUnions.ts, 47, 20)) +>third : Symbol(third, Decl(excessPropertyCheckWithUnions.ts, 47, 33)) // Freshness disappears after spreading a union declare let t0: { a: any, b: any } | { d: any, e: any } ->t0 : Symbol(t0, Decl(excessPropertyCheckWithUnions.ts, 52, 11)) ->a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 52, 17)) ->b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 52, 25)) ->d : Symbol(d, Decl(excessPropertyCheckWithUnions.ts, 52, 38)) ->e : Symbol(e, Decl(excessPropertyCheckWithUnions.ts, 52, 46)) +>t0 : Symbol(t0, Decl(excessPropertyCheckWithUnions.ts, 50, 11)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 50, 17)) +>b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 50, 25)) +>d : Symbol(d, Decl(excessPropertyCheckWithUnions.ts, 50, 38)) +>e : Symbol(e, Decl(excessPropertyCheckWithUnions.ts, 50, 46)) declare let t1: { a: any, b: any, c: any } | { c: any, d: any, e: any } ->t1 : Symbol(t1, Decl(excessPropertyCheckWithUnions.ts, 53, 11)) ->a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 53, 17)) ->b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 53, 25)) ->c : Symbol(c, Decl(excessPropertyCheckWithUnions.ts, 53, 33)) ->c : Symbol(c, Decl(excessPropertyCheckWithUnions.ts, 53, 46)) ->d : Symbol(d, Decl(excessPropertyCheckWithUnions.ts, 53, 54)) ->e : Symbol(e, Decl(excessPropertyCheckWithUnions.ts, 53, 62)) +>t1 : Symbol(t1, Decl(excessPropertyCheckWithUnions.ts, 51, 11)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 51, 17)) +>b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 51, 25)) +>c : Symbol(c, Decl(excessPropertyCheckWithUnions.ts, 51, 33)) +>c : Symbol(c, Decl(excessPropertyCheckWithUnions.ts, 51, 46)) +>d : Symbol(d, Decl(excessPropertyCheckWithUnions.ts, 51, 54)) +>e : Symbol(e, Decl(excessPropertyCheckWithUnions.ts, 51, 62)) let t2 = { ...t1 } ->t2 : Symbol(t2, Decl(excessPropertyCheckWithUnions.ts, 54, 3)) ->t1 : Symbol(t1, Decl(excessPropertyCheckWithUnions.ts, 53, 11)) +>t2 : Symbol(t2, Decl(excessPropertyCheckWithUnions.ts, 52, 3)) +>t1 : Symbol(t1, Decl(excessPropertyCheckWithUnions.ts, 51, 11)) t0 = t2 ->t0 : Symbol(t0, Decl(excessPropertyCheckWithUnions.ts, 52, 11)) ->t2 : Symbol(t2, Decl(excessPropertyCheckWithUnions.ts, 54, 3)) +>t0 : Symbol(t0, Decl(excessPropertyCheckWithUnions.ts, 50, 11)) +>t2 : Symbol(t2, Decl(excessPropertyCheckWithUnions.ts, 52, 3)) // Nested excess property checks work with discriminated unions type AN = { a: string } | { c: string } ->AN : Symbol(AN, Decl(excessPropertyCheckWithUnions.ts, 55, 7)) ->a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 58, 11)) ->c : Symbol(c, Decl(excessPropertyCheckWithUnions.ts, 58, 27)) +>AN : Symbol(AN, Decl(excessPropertyCheckWithUnions.ts, 53, 7)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 56, 11)) +>c : Symbol(c, Decl(excessPropertyCheckWithUnions.ts, 56, 27)) type BN = { b: string } ->BN : Symbol(BN, Decl(excessPropertyCheckWithUnions.ts, 58, 39)) ->b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 59, 11)) +>BN : Symbol(BN, Decl(excessPropertyCheckWithUnions.ts, 56, 39)) +>b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 57, 11)) type AB = { kind: "A", n: AN } | { kind: "B", n: BN } ->AB : Symbol(AB, Decl(excessPropertyCheckWithUnions.ts, 59, 23)) ->kind : Symbol(kind, Decl(excessPropertyCheckWithUnions.ts, 60, 11)) ->n : Symbol(n, Decl(excessPropertyCheckWithUnions.ts, 60, 22)) ->AN : Symbol(AN, Decl(excessPropertyCheckWithUnions.ts, 55, 7)) ->kind : Symbol(kind, Decl(excessPropertyCheckWithUnions.ts, 60, 34)) ->n : Symbol(n, Decl(excessPropertyCheckWithUnions.ts, 60, 45)) ->BN : Symbol(BN, Decl(excessPropertyCheckWithUnions.ts, 58, 39)) +>AB : Symbol(AB, Decl(excessPropertyCheckWithUnions.ts, 57, 23)) +>kind : Symbol(kind, Decl(excessPropertyCheckWithUnions.ts, 58, 11)) +>n : Symbol(n, Decl(excessPropertyCheckWithUnions.ts, 58, 22)) +>AN : Symbol(AN, Decl(excessPropertyCheckWithUnions.ts, 53, 7)) +>kind : Symbol(kind, Decl(excessPropertyCheckWithUnions.ts, 58, 34)) +>n : Symbol(n, Decl(excessPropertyCheckWithUnions.ts, 58, 45)) +>BN : Symbol(BN, Decl(excessPropertyCheckWithUnions.ts, 56, 39)) const abab: AB = { ->abab : Symbol(abab, Decl(excessPropertyCheckWithUnions.ts, 61, 5)) ->AB : Symbol(AB, Decl(excessPropertyCheckWithUnions.ts, 59, 23)) +>abab : Symbol(abab, Decl(excessPropertyCheckWithUnions.ts, 59, 5)) +>AB : Symbol(AB, Decl(excessPropertyCheckWithUnions.ts, 57, 23)) kind: "A", ->kind : Symbol(kind, Decl(excessPropertyCheckWithUnions.ts, 61, 18)) +>kind : Symbol(kind, Decl(excessPropertyCheckWithUnions.ts, 59, 18)) n: { ->n : Symbol(n, Decl(excessPropertyCheckWithUnions.ts, 62, 14)) +>n : Symbol(n, Decl(excessPropertyCheckWithUnions.ts, 60, 14)) a: "a", ->a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 63, 8)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 61, 8)) b: "b", // excess -- kind: "A" ->b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 64, 15)) +>b : Symbol(b, Decl(excessPropertyCheckWithUnions.ts, 62, 15)) } } const abac: AB = { ->abac : Symbol(abac, Decl(excessPropertyCheckWithUnions.ts, 68, 5)) ->AB : Symbol(AB, Decl(excessPropertyCheckWithUnions.ts, 59, 23)) +>abac : Symbol(abac, Decl(excessPropertyCheckWithUnions.ts, 66, 5)) +>AB : Symbol(AB, Decl(excessPropertyCheckWithUnions.ts, 57, 23)) kind: "A", ->kind : Symbol(kind, Decl(excessPropertyCheckWithUnions.ts, 68, 18)) +>kind : Symbol(kind, Decl(excessPropertyCheckWithUnions.ts, 66, 18)) n: { ->n : Symbol(n, Decl(excessPropertyCheckWithUnions.ts, 69, 14)) +>n : Symbol(n, Decl(excessPropertyCheckWithUnions.ts, 67, 14)) a: "a", ->a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 70, 8)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 68, 8)) c: "c", // ok -- kind: "A", an: { a: string } | { c: string } ->c : Symbol(c, Decl(excessPropertyCheckWithUnions.ts, 71, 15)) +>c : Symbol(c, Decl(excessPropertyCheckWithUnions.ts, 69, 15)) } } // Excess property checks must match all discriminable properties type Button = { tag: 'button'; type?: 'submit'; }; ->Button : Symbol(Button, Decl(excessPropertyCheckWithUnions.ts, 74, 1)) ->tag : Symbol(tag, Decl(excessPropertyCheckWithUnions.ts, 77, 15)) ->type : Symbol(type, Decl(excessPropertyCheckWithUnions.ts, 77, 30)) +>Button : Symbol(Button, Decl(excessPropertyCheckWithUnions.ts, 72, 1)) +>tag : Symbol(tag, Decl(excessPropertyCheckWithUnions.ts, 75, 15)) +>type : Symbol(type, Decl(excessPropertyCheckWithUnions.ts, 75, 30)) type Anchor = { tag: 'a'; type?: string; href: string }; ->Anchor : Symbol(Anchor, Decl(excessPropertyCheckWithUnions.ts, 77, 50)) ->tag : Symbol(tag, Decl(excessPropertyCheckWithUnions.ts, 78, 15)) ->type : Symbol(type, Decl(excessPropertyCheckWithUnions.ts, 78, 25)) ->href : Symbol(href, Decl(excessPropertyCheckWithUnions.ts, 78, 40)) +>Anchor : Symbol(Anchor, Decl(excessPropertyCheckWithUnions.ts, 75, 50)) +>tag : Symbol(tag, Decl(excessPropertyCheckWithUnions.ts, 76, 15)) +>type : Symbol(type, Decl(excessPropertyCheckWithUnions.ts, 76, 25)) +>href : Symbol(href, Decl(excessPropertyCheckWithUnions.ts, 76, 40)) type Union = Button | Anchor; ->Union : Symbol(Union, Decl(excessPropertyCheckWithUnions.ts, 78, 56)) ->Button : Symbol(Button, Decl(excessPropertyCheckWithUnions.ts, 74, 1)) ->Anchor : Symbol(Anchor, Decl(excessPropertyCheckWithUnions.ts, 77, 50)) +>Union : Symbol(Union, Decl(excessPropertyCheckWithUnions.ts, 76, 56)) +>Button : Symbol(Button, Decl(excessPropertyCheckWithUnions.ts, 72, 1)) +>Anchor : Symbol(Anchor, Decl(excessPropertyCheckWithUnions.ts, 75, 50)) const obj: Union = { ->obj : Symbol(obj, Decl(excessPropertyCheckWithUnions.ts, 81, 5)) ->Union : Symbol(Union, Decl(excessPropertyCheckWithUnions.ts, 78, 56)) +>obj : Symbol(obj, Decl(excessPropertyCheckWithUnions.ts, 79, 5)) +>Union : Symbol(Union, Decl(excessPropertyCheckWithUnions.ts, 76, 56)) tag: 'button', ->tag : Symbol(tag, Decl(excessPropertyCheckWithUnions.ts, 81, 20)) +>tag : Symbol(tag, Decl(excessPropertyCheckWithUnions.ts, 79, 20)) type: 'submit', ->type : Symbol(type, Decl(excessPropertyCheckWithUnions.ts, 82, 18)) +>type : Symbol(type, Decl(excessPropertyCheckWithUnions.ts, 80, 18)) // should have error here href: 'foo', ->href : Symbol(href, Decl(excessPropertyCheckWithUnions.ts, 83, 19)) +>href : Symbol(href, Decl(excessPropertyCheckWithUnions.ts, 81, 19)) }; // Repro from #34611 interface IValue { ->IValue : Symbol(IValue, Decl(excessPropertyCheckWithUnions.ts, 87, 2)) +>IValue : Symbol(IValue, Decl(excessPropertyCheckWithUnions.ts, 85, 2)) value: string ->value : Symbol(IValue.value, Decl(excessPropertyCheckWithUnions.ts, 91, 18)) +>value : Symbol(IValue.value, Decl(excessPropertyCheckWithUnions.ts, 89, 18)) } -interface StringKeys { ->StringKeys : Symbol(StringKeys, Decl(excessPropertyCheckWithUnions.ts, 93, 1)) +interface StringKeys { +>StringKeys : Symbol(StringKeys, Decl(excessPropertyCheckWithUnions.ts, 91, 1)) [propertyName: string]: IValue; ->propertyName : Symbol(propertyName, Decl(excessPropertyCheckWithUnions.ts, 96, 5)) ->IValue : Symbol(IValue, Decl(excessPropertyCheckWithUnions.ts, 87, 2)) +>propertyName : Symbol(propertyName, Decl(excessPropertyCheckWithUnions.ts, 94, 5)) +>IValue : Symbol(IValue, Decl(excessPropertyCheckWithUnions.ts, 85, 2)) }; interface NumberKeys { ->NumberKeys : Symbol(NumberKeys, Decl(excessPropertyCheckWithUnions.ts, 97, 2)) +>NumberKeys : Symbol(NumberKeys, Decl(excessPropertyCheckWithUnions.ts, 95, 2)) [propertyName: number]: IValue; ->propertyName : Symbol(propertyName, Decl(excessPropertyCheckWithUnions.ts, 100, 5)) ->IValue : Symbol(IValue, Decl(excessPropertyCheckWithUnions.ts, 87, 2)) +>propertyName : Symbol(propertyName, Decl(excessPropertyCheckWithUnions.ts, 98, 5)) +>IValue : Symbol(IValue, Decl(excessPropertyCheckWithUnions.ts, 85, 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)) +>ObjectDataSpecification : Symbol(ObjectDataSpecification, Decl(excessPropertyCheckWithUnions.ts, 99, 1)) +>StringKeys : Symbol(StringKeys, Decl(excessPropertyCheckWithUnions.ts, 91, 1)) +>NumberKeys : Symbol(NumberKeys, Decl(excessPropertyCheckWithUnions.ts, 95, 2)) const dataSpecification: ObjectDataSpecification = { // Error ->dataSpecification : Symbol(dataSpecification, Decl(excessPropertyCheckWithUnions.ts, 106, 5)) ->ObjectDataSpecification : Symbol(ObjectDataSpecification, Decl(excessPropertyCheckWithUnions.ts, 101, 1)) +>dataSpecification : Symbol(dataSpecification, Decl(excessPropertyCheckWithUnions.ts, 104, 5)) +>ObjectDataSpecification : Symbol(ObjectDataSpecification, Decl(excessPropertyCheckWithUnions.ts, 99, 1)) foo: "asdfsadffsd" ->foo : Symbol(foo, Decl(excessPropertyCheckWithUnions.ts, 106, 52)) +>foo : Symbol(foo, Decl(excessPropertyCheckWithUnions.ts, 104, 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)) +>obj1 : Symbol(obj1, Decl(excessPropertyCheckWithUnions.ts, 110, 5)) +>x : Symbol(x, Decl(excessPropertyCheckWithUnions.ts, 110, 15)) +>x : Symbol(x, Decl(excessPropertyCheckWithUnions.ts, 110, 41)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 110, 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)) +>obj2 : Symbol(obj2, Decl(excessPropertyCheckWithUnions.ts, 111, 5)) +>x : Symbol(x, Decl(excessPropertyCheckWithUnions.ts, 111, 15)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 111, 39)) +>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 111, 55)) +>c : Symbol(c, Decl(excessPropertyCheckWithUnions.ts, 111, 61)) // Repro from #33732 interface I1 { ->I1 : Symbol(I1, Decl(excessPropertyCheckWithUnions.ts, 113, 73)) +>I1 : Symbol(I1, Decl(excessPropertyCheckWithUnions.ts, 111, 73)) prop1: string; ->prop1 : Symbol(I1.prop1, Decl(excessPropertyCheckWithUnions.ts, 117, 14)) +>prop1 : Symbol(I1.prop1, Decl(excessPropertyCheckWithUnions.ts, 115, 14)) } interface I2 { ->I2 : Symbol(I2, Decl(excessPropertyCheckWithUnions.ts, 119, 1)) +>I2 : Symbol(I2, Decl(excessPropertyCheckWithUnions.ts, 117, 1)) prop2: string; ->prop2 : Symbol(I2.prop2, Decl(excessPropertyCheckWithUnions.ts, 121, 14)) +>prop2 : Symbol(I2.prop2, Decl(excessPropertyCheckWithUnions.ts, 119, 14)) } interface I3 extends Record { ->I3 : Symbol(I3, Decl(excessPropertyCheckWithUnions.ts, 123, 1)) +>I3 : Symbol(I3, Decl(excessPropertyCheckWithUnions.ts, 121, 1)) >Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) } type Properties = ->Properties : Symbol(Properties, Decl(excessPropertyCheckWithUnions.ts, 127, 1)) +>Properties : Symbol(Properties, Decl(excessPropertyCheckWithUnions.ts, 125, 1)) | { [key: string]: never } ->key : Symbol(key, Decl(excessPropertyCheckWithUnions.ts, 130, 9)) +>key : Symbol(key, Decl(excessPropertyCheckWithUnions.ts, 128, 9)) | I1 ->I1 : Symbol(I1, Decl(excessPropertyCheckWithUnions.ts, 113, 73)) +>I1 : Symbol(I1, Decl(excessPropertyCheckWithUnions.ts, 111, 73)) | I2 ->I2 : Symbol(I2, Decl(excessPropertyCheckWithUnions.ts, 119, 1)) +>I2 : Symbol(I2, Decl(excessPropertyCheckWithUnions.ts, 117, 1)) | I3 ->I3 : Symbol(I3, Decl(excessPropertyCheckWithUnions.ts, 123, 1)) +>I3 : Symbol(I3, Decl(excessPropertyCheckWithUnions.ts, 121, 1)) ; declare const prop1: string; ->prop1 : Symbol(prop1, Decl(excessPropertyCheckWithUnions.ts, 137, 13)) +>prop1 : Symbol(prop1, Decl(excessPropertyCheckWithUnions.ts, 135, 13)) declare const prop2: string | undefined; ->prop2 : Symbol(prop2, Decl(excessPropertyCheckWithUnions.ts, 138, 13)) +>prop2 : Symbol(prop2, Decl(excessPropertyCheckWithUnions.ts, 136, 13)) function F1(_arg: { props: Properties }) { } ->F1 : Symbol(F1, Decl(excessPropertyCheckWithUnions.ts, 138, 40)) ->_arg : Symbol(_arg, Decl(excessPropertyCheckWithUnions.ts, 140, 12)) ->props : Symbol(props, Decl(excessPropertyCheckWithUnions.ts, 140, 19)) ->Properties : Symbol(Properties, Decl(excessPropertyCheckWithUnions.ts, 127, 1)) +>F1 : Symbol(F1, Decl(excessPropertyCheckWithUnions.ts, 136, 40)) +>_arg : Symbol(_arg, Decl(excessPropertyCheckWithUnions.ts, 138, 12)) +>props : Symbol(props, Decl(excessPropertyCheckWithUnions.ts, 138, 19)) +>Properties : Symbol(Properties, Decl(excessPropertyCheckWithUnions.ts, 125, 1)) F1({ ->F1 : Symbol(F1, Decl(excessPropertyCheckWithUnions.ts, 138, 40)) +>F1 : Symbol(F1, Decl(excessPropertyCheckWithUnions.ts, 136, 40)) props: { ->props : Symbol(props, Decl(excessPropertyCheckWithUnions.ts, 141, 4)) +>props : Symbol(props, Decl(excessPropertyCheckWithUnions.ts, 139, 4)) prop1, ->prop1 : Symbol(prop1, Decl(excessPropertyCheckWithUnions.ts, 142, 12)) +>prop1 : Symbol(prop1, Decl(excessPropertyCheckWithUnions.ts, 140, 12)) prop2, ->prop2 : Symbol(prop2, Decl(excessPropertyCheckWithUnions.ts, 143, 14)) +>prop2 : Symbol(prop2, Decl(excessPropertyCheckWithUnions.ts, 141, 14)) }, }); function F2(_props: Properties) { } ->F2 : Symbol(F2, Decl(excessPropertyCheckWithUnions.ts, 146, 3)) ->_props : Symbol(_props, Decl(excessPropertyCheckWithUnions.ts, 148, 12)) ->Properties : Symbol(Properties, Decl(excessPropertyCheckWithUnions.ts, 127, 1)) +>F2 : Symbol(F2, Decl(excessPropertyCheckWithUnions.ts, 144, 3)) +>_props : Symbol(_props, Decl(excessPropertyCheckWithUnions.ts, 146, 12)) +>Properties : Symbol(Properties, Decl(excessPropertyCheckWithUnions.ts, 125, 1)) F2({ ->F2 : Symbol(F2, Decl(excessPropertyCheckWithUnions.ts, 146, 3)) +>F2 : Symbol(F2, Decl(excessPropertyCheckWithUnions.ts, 144, 3)) prop1, ->prop1 : Symbol(prop1, Decl(excessPropertyCheckWithUnions.ts, 149, 4)) +>prop1 : Symbol(prop1, Decl(excessPropertyCheckWithUnions.ts, 147, 4)) prop2, ->prop2 : Symbol(prop2, Decl(excessPropertyCheckWithUnions.ts, 150, 10)) +>prop2 : Symbol(prop2, Decl(excessPropertyCheckWithUnions.ts, 148, 10)) }); diff --git a/tests/baselines/reference/excessPropertyCheckWithUnions.types b/tests/baselines/reference/excessPropertyCheckWithUnions.types index 2b012e13eb14c..699a13fb48640 100644 --- a/tests/baselines/reference/excessPropertyCheckWithUnions.types +++ b/tests/baselines/reference/excessPropertyCheckWithUnions.types @@ -126,9 +126,7 @@ amb = { tag: "A", y: 12, extra: 12 } >extra : number >12 : 12 -// assignability errors still work. -// But note that the error for `z: true` is the fallback one of reporting on -// the last constituent since assignability error reporting can't find a single best discriminant either. +// assignability errors still work amb = { tag: "A" } >amb = { tag: "A" } : { tag: "A"; } >amb : Ambiguous @@ -137,12 +135,12 @@ amb = { tag: "A" } >"A" : "A" amb = { tag: "A", z: true } ->amb = { tag: "A", z: true } : { tag: "A"; z: true; } +>amb = { tag: "A", z: true } : { tag: "A"; z: boolean; } >amb : Ambiguous ->{ tag: "A", z: true } : { tag: "A"; z: true; } +>{ tag: "A", z: true } : { tag: "A"; z: boolean; } >tag : "A" >"A" : "A" ->z : true +>z : boolean >true : true type Overlapping = @@ -319,7 +317,7 @@ interface IValue { >value : string } -interface StringKeys { +interface StringKeys { [propertyName: string]: IValue; >propertyName : string diff --git a/tests/baselines/reference/objectLiteralNormalization.errors.txt b/tests/baselines/reference/objectLiteralNormalization.errors.txt index e057800725e21..a6ffc718f913c 100644 --- a/tests/baselines/reference/objectLiteralNormalization.errors.txt +++ b/tests/baselines/reference/objectLiteralNormalization.errors.txt @@ -1,6 +1,7 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(7,14): error TS2322: Type 'number' is not assignable to type 'string'. tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(8,1): error TS2322: Type '{ b: string; }' is not assignable to type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'. - Type '{ b: string; }' is missing the following properties from type '{ a: number; b: string; c: boolean; }': a, c + Type '{ b: string; }' is not assignable to type '{ a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'. + Type '{ b: string; }' is missing the following properties from type '{ a: number; b: string; c: boolean; }': a, c tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(9,1): error TS2322: Type '{ c: true; }' is not assignable to type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'. Type '{ c: true; }' is missing the following properties from type '{ a: number; b: string; c: boolean; }': a, b tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(17,1): error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }'. @@ -27,7 +28,8 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts a1 = { b: "y" }; // Error ~~ !!! error TS2322: Type '{ b: string; }' is not assignable to type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'. -!!! error TS2322: Type '{ b: string; }' is missing the following properties from type '{ a: number; b: string; c: boolean; }': a, c +!!! error TS2322: Type '{ b: string; }' is not assignable to type '{ a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'. +!!! error TS2322: Type '{ b: string; }' is missing the following properties from type '{ a: number; b: string; c: boolean; }': a, c a1 = { c: true }; // Error ~~ !!! error TS2322: Type '{ c: true; }' is not assignable to type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'. diff --git a/tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts b/tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts index 5f7abedc1f42a..1288cf9350aad 100644 --- a/tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts +++ b/tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts @@ -42,7 +42,7 @@ const a: DisjointDiscriminants = { p4: "hello" }; -// This has no excess error because variant one and three are both applicable. +// This has excess error because variant two is not applicable. const b: DisjointDiscriminants = { p1: 'left', p2: true, @@ -57,3 +57,83 @@ const c: DisjointDiscriminants = { p3: 42, p4: "hello" }; + +// Repro from #51873 + +interface Common { + type: "A" | "B" | "C" | "D"; + n: number; +} +interface A { + type: "A"; + a?: number; +} +interface B { + type: "B"; + b?: number; +} + +type CommonWithOverlappingOptionals = Common | (Common & A) | (Common & B); + +// Should reject { b } because reduced to Common | (Common & A) +const c1: CommonWithOverlappingOptionals = { + type: "A", + n: 1, + a: 1, + b: 1 // excess property +} + +type CommonWithDisjointOverlappingOptionals = Common | A | B; + +// Should still reject { b } because reduced to Common | A, even though these are now disjoint +const c2: CommonWithDisjointOverlappingOptionals = { + type: "A", + n: 1, + a: 1, + b: 1 // excess property +} + +// Repro from https://github.com/microsoft/TypeScript/pull/51884#issuecomment-1472736068 + +export type BaseAttribute = { + type?: string | undefined; + required?: boolean | undefined; + defaultsTo?: T | undefined; +}; + +export type Attribute = + | string + | StringAttribute + | NumberAttribute + | OneToOneAttribute + +export type Attribute2 = + | string + | StringAttribute + | NumberAttribute + +export type StringAttribute = BaseAttribute & { + type: 'string'; +}; + +export type NumberAttribute = BaseAttribute & { + type: 'number'; + autoIncrement?: boolean | undefined; +}; + +export type OneToOneAttribute = BaseAttribute & { + model: string; +}; + +// both should error due to excess properties +const attributes: Attribute = { + type: 'string', + autoIncrement: true, + required: true, +}; + +const attributes2: Attribute2 = { + type: 'string', + autoIncrement: true, + required: true, +}; diff --git a/tests/cases/compiler/excessPropertyCheckWithUnions.ts b/tests/cases/compiler/excessPropertyCheckWithUnions.ts index 4f8ea87a3ceb2..6f26597ae912c 100644 --- a/tests/cases/compiler/excessPropertyCheckWithUnions.ts +++ b/tests/cases/compiler/excessPropertyCheckWithUnions.ts @@ -34,9 +34,7 @@ amb = { tag: "A", x: "hi", y: 12 } amb = { tag: "A", x: "hi", extra: 12 } amb = { tag: "A", y: 12, extra: 12 } -// assignability errors still work. -// But note that the error for `z: true` is the fallback one of reporting on -// the last constituent since assignability error reporting can't find a single best discriminant either. +// assignability errors still work amb = { tag: "A" } amb = { tag: "A", z: true } @@ -94,7 +92,7 @@ interface IValue { value: string } -interface StringKeys { +interface StringKeys { [propertyName: string]: IValue; };