Consider all union types matching discriminator for excess property checks (#51884)

Co-authored-by: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
This commit is contained in:
Nebojša Cvetković 2023-03-20 20:50:23 +00:00 committed by GitHub
parent 3ba3ace236
commit 4fcb8b8be6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 814 additions and 198 deletions

View File

@ -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]));
}
/**

View File

@ -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<T> {
@ -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<T> = {
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<string> & {
type: 'string';
};
export type NumberAttribute = BaseAttribute<number> & {
type: 'number';
autoIncrement?: boolean | undefined;
};
export type OneToOneAttribute = BaseAttribute<any> & {
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,
};

View File

@ -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<T> = {
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<string> & {
type: 'string';
};
export type NumberAttribute = BaseAttribute<number> & {
type: 'number';
autoIncrement?: boolean | undefined;
};
export type OneToOneAttribute = BaseAttribute<any> & {
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,
};

View File

@ -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<T> = {
>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<string> & {
>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<number> & {
>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<any> & {
>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))
};

View File

@ -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<T> = {
>BaseAttribute : BaseAttribute<T>
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<string> & {
>StringAttribute : BaseAttribute<string> & { type: 'string'; }
type: 'string';
>type : "string"
};
export type NumberAttribute = BaseAttribute<number> & {
>NumberAttribute : BaseAttribute<number> & { type: 'number'; autoIncrement?: boolean | undefined; }
type: 'number';
>type : "number"
autoIncrement?: boolean | undefined;
>autoIncrement : boolean
};
export type OneToOneAttribute = BaseAttribute<any> & {
>OneToOneAttribute : BaseAttribute<any> & { 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
};

View File

@ -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;
};

View File

@ -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;

View File

@ -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<string, string> {
>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))
});

View File

@ -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

View File

@ -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; }'.

View File

@ -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<T> = {
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<string> & {
type: 'string';
};
export type NumberAttribute = BaseAttribute<number> & {
type: 'number';
autoIncrement?: boolean | undefined;
};
export type OneToOneAttribute = BaseAttribute<any> & {
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,
};

View File

@ -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;
};