// @strict: true type ADT = { tag: "A", a1: string } | { tag: "D", d20: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 } | { tag: "T", } let wrong: ADT = { tag: "T", a1: "extra" } wrong = { tag: "A", d20: 12 } wrong = { tag: "D" } type Ambiguous = { tag: "A", x: string } | { tag: "A", y: number } | { tag: "B", z: boolean } | { tag: "C" } let amb: Ambiguous // no error for ambiguous tag, even when it could satisfy both constituents at once amb = { tag: "A", x: "hi" } amb = { tag: "A", y: 12 } 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. amb = { tag: "A" } amb = { tag: "A", z: true } type Overlapping = | { a: 1, b: 1, first: string } | { a: 2, second: string } | { b: 3, third: string } let over: Overlapping // these two are still errors despite their doubled up discriminants over = { a: 1, b: 1, first: "ok", second: "error" } over = { a: 1, b: 1, first: "ok", third: "error" } // Freshness disappears after spreading a union declare let t0: { a: any, b: any } | { d: any, e: any } declare let t1: { a: any, b: any, c: any } | { c: any, d: any, e: any } let t2 = { ...t1 } t0 = t2 // Nested excess property checks work with discriminated unions type AN = { a: string } | { c: string } type BN = { b: string } type AB = { kind: "A", n: AN } | { kind: "B", n: BN } const abab: AB = { kind: "A", n: { a: "a", b: "b", // excess -- kind: "A" } } const abac: AB = { kind: "A", n: { a: "a", c: "c", // ok -- kind: "A", an: { a: string } | { c: string } } } // Excess property checks must match all discriminable properties type Button = { tag: 'button'; type?: 'submit'; }; type Anchor = { tag: 'a'; type?: string; href: string }; type Union = Button | Anchor; const obj: Union = { tag: 'button', type: 'submit', // should have error here href: 'foo', }; // Repro from #34611 interface IValue { value: string } interface StringKeys { [propertyName: string]: IValue; }; interface NumberKeys { [propertyName: number]: IValue; } type ObjectDataSpecification = StringKeys | NumberKeys; const dataSpecification: ObjectDataSpecification = { // Error foo: "asdfsadffsd" }; // Repro from #34611 const obj1: { [x: string]: number } | { [x: number]: number } = { a: 'abc' }; // Error const obj2: { [x: string]: number } | { a: number } = { a: 5, c: 'abc' }; // Error // Repro from #33732 interface I1 { prop1: string; } interface I2 { prop2: string; } interface I3 extends Record { } type Properties = | { [key: string]: never } | I1 | I2 | I3 ; declare const prop1: string; declare const prop2: string | undefined; function F1(_arg: { props: Properties }) { } F1({ props: { prop1, prop2, }, }); function F2(_props: Properties) { } F2({ prop1, prop2, });