Discriminate contextual types (#19733)
* Discriminate contextual types * Invert conditional * Update findMatchingDiscriminantType and baselines
This commit is contained in:
parent
d6436f13e5
commit
d79c37cd19
|
@ -9269,20 +9269,24 @@ namespace ts {
|
||||||
return Ternary.False;
|
return Ternary.False;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep this up-to-date with the same logic within `getApparentTypeOfContextualType`, since they should behave similarly
|
||||||
function findMatchingDiscriminantType(source: Type, target: UnionOrIntersectionType) {
|
function findMatchingDiscriminantType(source: Type, target: UnionOrIntersectionType) {
|
||||||
let match: Type;
|
let match: Type;
|
||||||
const sourceProperties = getPropertiesOfObjectType(source);
|
const sourceProperties = getPropertiesOfObjectType(source);
|
||||||
if (sourceProperties) {
|
if (sourceProperties) {
|
||||||
const sourceProperty = findSingleDiscriminantProperty(sourceProperties, target);
|
const sourcePropertiesFiltered = findDiscriminantProperties(sourceProperties, target);
|
||||||
if (sourceProperty) {
|
if (sourcePropertiesFiltered) {
|
||||||
const sourceType = getTypeOfSymbol(sourceProperty);
|
for (const sourceProperty of sourcePropertiesFiltered) {
|
||||||
for (const type of target.types) {
|
const sourceType = getTypeOfSymbol(sourceProperty);
|
||||||
const targetType = getTypeOfPropertyOfType(type, sourceProperty.escapedName);
|
for (const type of target.types) {
|
||||||
if (targetType && isRelatedTo(sourceType, targetType)) {
|
const targetType = getTypeOfPropertyOfType(type, sourceProperty.escapedName);
|
||||||
if (match) {
|
if (targetType && isRelatedTo(sourceType, targetType)) {
|
||||||
return undefined;
|
if (type === match) continue; // Finding multiple fields which discriminate to the same type is fine
|
||||||
|
if (match) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
match = type;
|
||||||
}
|
}
|
||||||
match = type;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11396,14 +11400,15 @@ namespace ts {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findSingleDiscriminantProperty(sourceProperties: Symbol[], target: Type): Symbol | undefined {
|
function findDiscriminantProperties(sourceProperties: Symbol[], target: Type): Symbol[] | undefined {
|
||||||
let result: Symbol;
|
let result: Symbol[];
|
||||||
for (const sourceProperty of sourceProperties) {
|
for (const sourceProperty of sourceProperties) {
|
||||||
if (isDiscriminantProperty(target, sourceProperty.escapedName)) {
|
if (isDiscriminantProperty(target, sourceProperty.escapedName)) {
|
||||||
if (result) {
|
if (result) {
|
||||||
return undefined;
|
result.push(sourceProperty);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
result = sourceProperty;
|
result = [sourceProperty];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -13691,8 +13696,32 @@ namespace ts {
|
||||||
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
|
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
|
||||||
// be "pushed" onto a node using the contextualType property.
|
// be "pushed" onto a node using the contextualType property.
|
||||||
function getApparentTypeOfContextualType(node: Expression): Type {
|
function getApparentTypeOfContextualType(node: Expression): Type {
|
||||||
const type = getContextualType(node);
|
let contextualType = getContextualType(node);
|
||||||
return type && mapType(type, getApparentType);
|
contextualType = contextualType && mapType(contextualType, getApparentType);
|
||||||
|
if (!(contextualType && contextualType.flags & TypeFlags.Union && isObjectLiteralExpression(node))) {
|
||||||
|
return contextualType;
|
||||||
|
}
|
||||||
|
// Keep the below up-to-date with the work done within `isRelatedTo` by `findMatchingDiscriminantType`
|
||||||
|
let match: Type | undefined;
|
||||||
|
propLoop: for (const prop of node.properties) {
|
||||||
|
if (!prop.symbol) continue;
|
||||||
|
if (prop.kind !== SyntaxKind.PropertyAssignment) continue;
|
||||||
|
if (isDiscriminantProperty(contextualType, prop.symbol.escapedName)) {
|
||||||
|
const discriminatingType = getTypeOfNode(prop.initializer);
|
||||||
|
for (const type of (contextualType as UnionType).types) {
|
||||||
|
const targetType = getTypeOfPropertyOfType(type, prop.symbol.escapedName);
|
||||||
|
if (targetType && checkTypeAssignableTo(discriminatingType, targetType, /*errorNode*/ undefined)) {
|
||||||
|
if (match) {
|
||||||
|
if (type === match) continue; // Finding multiple fields which discriminate to the same type is fine
|
||||||
|
match = undefined;
|
||||||
|
break propLoop;
|
||||||
|
}
|
||||||
|
match = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match || contextualType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
//// [contextuallyTypedByDiscriminableUnion.ts]
|
||||||
|
type ADT = {
|
||||||
|
kind: "a",
|
||||||
|
method(x: string): number;
|
||||||
|
} | {
|
||||||
|
kind: "b",
|
||||||
|
method(x: number): string;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function invoke(item: ADT) {
|
||||||
|
if (item.kind === "a") {
|
||||||
|
item.method("");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.method(42);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invoke({
|
||||||
|
kind: "a",
|
||||||
|
method(a) {
|
||||||
|
return +a;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
//// [contextuallyTypedByDiscriminableUnion.js]
|
||||||
|
function invoke(item) {
|
||||||
|
if (item.kind === "a") {
|
||||||
|
item.method("");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.method(42);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
invoke({
|
||||||
|
kind: "a",
|
||||||
|
method: function (a) {
|
||||||
|
return +a;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,60 @@
|
||||||
|
=== tests/cases/compiler/contextuallyTypedByDiscriminableUnion.ts ===
|
||||||
|
type ADT = {
|
||||||
|
>ADT : Symbol(ADT, Decl(contextuallyTypedByDiscriminableUnion.ts, 0, 0))
|
||||||
|
|
||||||
|
kind: "a",
|
||||||
|
>kind : Symbol(kind, Decl(contextuallyTypedByDiscriminableUnion.ts, 0, 12))
|
||||||
|
|
||||||
|
method(x: string): number;
|
||||||
|
>method : Symbol(method, Decl(contextuallyTypedByDiscriminableUnion.ts, 1, 14))
|
||||||
|
>x : Symbol(x, Decl(contextuallyTypedByDiscriminableUnion.ts, 2, 11))
|
||||||
|
|
||||||
|
} | {
|
||||||
|
kind: "b",
|
||||||
|
>kind : Symbol(kind, Decl(contextuallyTypedByDiscriminableUnion.ts, 3, 5))
|
||||||
|
|
||||||
|
method(x: number): string;
|
||||||
|
>method : Symbol(method, Decl(contextuallyTypedByDiscriminableUnion.ts, 4, 14))
|
||||||
|
>x : Symbol(x, Decl(contextuallyTypedByDiscriminableUnion.ts, 5, 11))
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function invoke(item: ADT) {
|
||||||
|
>invoke : Symbol(invoke, Decl(contextuallyTypedByDiscriminableUnion.ts, 6, 2))
|
||||||
|
>item : Symbol(item, Decl(contextuallyTypedByDiscriminableUnion.ts, 9, 16))
|
||||||
|
>ADT : Symbol(ADT, Decl(contextuallyTypedByDiscriminableUnion.ts, 0, 0))
|
||||||
|
|
||||||
|
if (item.kind === "a") {
|
||||||
|
>item.kind : Symbol(kind, Decl(contextuallyTypedByDiscriminableUnion.ts, 0, 12), Decl(contextuallyTypedByDiscriminableUnion.ts, 3, 5))
|
||||||
|
>item : Symbol(item, Decl(contextuallyTypedByDiscriminableUnion.ts, 9, 16))
|
||||||
|
>kind : Symbol(kind, Decl(contextuallyTypedByDiscriminableUnion.ts, 0, 12), Decl(contextuallyTypedByDiscriminableUnion.ts, 3, 5))
|
||||||
|
|
||||||
|
item.method("");
|
||||||
|
>item.method : Symbol(method, Decl(contextuallyTypedByDiscriminableUnion.ts, 1, 14))
|
||||||
|
>item : Symbol(item, Decl(contextuallyTypedByDiscriminableUnion.ts, 9, 16))
|
||||||
|
>method : Symbol(method, Decl(contextuallyTypedByDiscriminableUnion.ts, 1, 14))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.method(42);
|
||||||
|
>item.method : Symbol(method, Decl(contextuallyTypedByDiscriminableUnion.ts, 4, 14))
|
||||||
|
>item : Symbol(item, Decl(contextuallyTypedByDiscriminableUnion.ts, 9, 16))
|
||||||
|
>method : Symbol(method, Decl(contextuallyTypedByDiscriminableUnion.ts, 4, 14))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invoke({
|
||||||
|
>invoke : Symbol(invoke, Decl(contextuallyTypedByDiscriminableUnion.ts, 6, 2))
|
||||||
|
|
||||||
|
kind: "a",
|
||||||
|
>kind : Symbol(kind, Decl(contextuallyTypedByDiscriminableUnion.ts, 18, 8))
|
||||||
|
|
||||||
|
method(a) {
|
||||||
|
>method : Symbol(method, Decl(contextuallyTypedByDiscriminableUnion.ts, 19, 14))
|
||||||
|
>a : Symbol(a, Decl(contextuallyTypedByDiscriminableUnion.ts, 20, 11))
|
||||||
|
|
||||||
|
return +a;
|
||||||
|
>a : Symbol(a, Decl(contextuallyTypedByDiscriminableUnion.ts, 20, 11))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
=== tests/cases/compiler/contextuallyTypedByDiscriminableUnion.ts ===
|
||||||
|
type ADT = {
|
||||||
|
>ADT : ADT
|
||||||
|
|
||||||
|
kind: "a",
|
||||||
|
>kind : "a"
|
||||||
|
|
||||||
|
method(x: string): number;
|
||||||
|
>method : (x: string) => number
|
||||||
|
>x : string
|
||||||
|
|
||||||
|
} | {
|
||||||
|
kind: "b",
|
||||||
|
>kind : "b"
|
||||||
|
|
||||||
|
method(x: number): string;
|
||||||
|
>method : (x: number) => string
|
||||||
|
>x : number
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function invoke(item: ADT) {
|
||||||
|
>invoke : (item: ADT) => void
|
||||||
|
>item : ADT
|
||||||
|
>ADT : ADT
|
||||||
|
|
||||||
|
if (item.kind === "a") {
|
||||||
|
>item.kind === "a" : boolean
|
||||||
|
>item.kind : "a" | "b"
|
||||||
|
>item : ADT
|
||||||
|
>kind : "a" | "b"
|
||||||
|
>"a" : "a"
|
||||||
|
|
||||||
|
item.method("");
|
||||||
|
>item.method("") : number
|
||||||
|
>item.method : (x: string) => number
|
||||||
|
>item : { kind: "a"; method(x: string): number; }
|
||||||
|
>method : (x: string) => number
|
||||||
|
>"" : ""
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.method(42);
|
||||||
|
>item.method(42) : string
|
||||||
|
>item.method : (x: number) => string
|
||||||
|
>item : { kind: "b"; method(x: number): string; }
|
||||||
|
>method : (x: number) => string
|
||||||
|
>42 : 42
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invoke({
|
||||||
|
>invoke({ kind: "a", method(a) { return +a; }}) : void
|
||||||
|
>invoke : (item: ADT) => void
|
||||||
|
>{ kind: "a", method(a) { return +a; }} : { kind: "a"; method(a: string): number; }
|
||||||
|
|
||||||
|
kind: "a",
|
||||||
|
>kind : string
|
||||||
|
>"a" : "a"
|
||||||
|
|
||||||
|
method(a) {
|
||||||
|
>method : (a: string) => number
|
||||||
|
>a : string
|
||||||
|
|
||||||
|
return +a;
|
||||||
|
>+a : number
|
||||||
|
>a : string
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
tests/cases/compiler/excessPropertyCheckWithUnions.ts(10,30): error TS2322: Type '{ tag: "T"; a1: string; }' is not assignable to type 'ADT'.
|
tests/cases/compiler/excessPropertyCheckWithUnions.ts(10,30): error TS2322: Type '{ tag: "T"; a1: string; }' is not assignable to type 'ADT'.
|
||||||
Object literal may only specify known properties, and 'a1' does not exist in type '{ tag: "T"; }'.
|
Object literal may only specify known properties, and 'a1' does not exist in type '{ tag: "T"; }'.
|
||||||
tests/cases/compiler/excessPropertyCheckWithUnions.ts(11,21): error TS2322: Type '{ tag: "A"; d20: 12; }' is not assignable to type 'ADT'.
|
tests/cases/compiler/excessPropertyCheckWithUnions.ts(11,21): error TS2322: Type '{ tag: "A"; d20: number; }' is not assignable to type 'ADT'.
|
||||||
Object literal may only specify known properties, and 'd20' does not exist in type '{ tag: "A"; a1: string; }'.
|
Object literal may only specify known properties, and 'd20' does not exist in type '{ tag: "A"; a1: string; }'.
|
||||||
tests/cases/compiler/excessPropertyCheckWithUnions.ts(12,1): error TS2322: Type '{ tag: "D"; }' is not assignable to type 'ADT'.
|
tests/cases/compiler/excessPropertyCheckWithUnions.ts(12,1): error TS2322: Type '{ tag: "D"; }' is not assignable to type 'ADT'.
|
||||||
Type '{ tag: "D"; }' is not assignable to type '{ tag: "D"; d20: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20; }'.
|
Type '{ tag: "D"; }' is not assignable to type '{ tag: "D"; d20: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20; }'.
|
||||||
|
@ -17,9 +17,13 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(40,1): error TS2322: Type
|
||||||
Type '{ tag: "A"; z: true; }' is not assignable to type '{ tag: "C"; }'.
|
Type '{ tag: "A"; z: true; }' is not assignable to type '{ tag: "C"; }'.
|
||||||
Types of property 'tag' are incompatible.
|
Types of property 'tag' are incompatible.
|
||||||
Type '"A"' is not assignable to type '"C"'.
|
Type '"A"' is not assignable to type '"C"'.
|
||||||
|
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 'second' does not exist in type '{ a: 1; b: 1; first: string; }'.
|
||||||
|
tests/cases/compiler/excessPropertyCheckWithUnions.ts(50,35): error TS2322: Type '{ a: 1; b: 1; first: string; third: string; }' is not assignable to type 'Overlapping'.
|
||||||
|
Object literal may only specify known properties, and 'third' does not exist in type '{ a: 1; b: 1; first: string; }'.
|
||||||
|
|
||||||
|
|
||||||
==== tests/cases/compiler/excessPropertyCheckWithUnions.ts (7 errors) ====
|
==== tests/cases/compiler/excessPropertyCheckWithUnions.ts (9 errors) ====
|
||||||
type ADT = {
|
type ADT = {
|
||||||
tag: "A",
|
tag: "A",
|
||||||
a1: string
|
a1: string
|
||||||
|
@ -35,7 +39,7 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(40,1): error TS2322: Type
|
||||||
!!! error TS2322: Object literal may only specify known properties, and 'a1' does not exist in type '{ tag: "T"; }'.
|
!!! error TS2322: Object literal may only specify known properties, and 'a1' does not exist in type '{ tag: "T"; }'.
|
||||||
wrong = { tag: "A", d20: 12 }
|
wrong = { tag: "A", d20: 12 }
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
!!! error TS2322: Type '{ tag: "A"; d20: 12; }' is not assignable to type 'ADT'.
|
!!! error TS2322: Type '{ tag: "A"; d20: number; }' is not assignable to type 'ADT'.
|
||||||
!!! error TS2322: Object literal may only specify known properties, and 'd20' does not exist in type '{ tag: "A"; a1: string; }'.
|
!!! error TS2322: Object literal may only specify known properties, and 'd20' does not exist in type '{ tag: "A"; a1: string; }'.
|
||||||
wrong = { tag: "D" }
|
wrong = { tag: "D" }
|
||||||
~~~~~
|
~~~~~
|
||||||
|
@ -93,9 +97,15 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(40,1): error TS2322: Type
|
||||||
| { b: 3, third: string }
|
| { b: 3, third: string }
|
||||||
let over: Overlapping
|
let over: Overlapping
|
||||||
|
|
||||||
// these two are not reported because there are two discriminant properties
|
// 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", second: "error" }
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
!!! error TS2322: Type '{ a: 1; b: 1; first: string; second: string; }' is not assignable to type 'Overlapping'.
|
||||||
|
!!! error TS2322: Object literal may only specify known properties, and 'second' does not exist in type '{ a: 1; b: 1; first: string; }'.
|
||||||
over = { a: 1, b: 1, first: "ok", third: "error" }
|
over = { a: 1, b: 1, first: "ok", third: "error" }
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
!!! error TS2322: Type '{ a: 1; b: 1; first: string; third: string; }' is not assignable to type 'Overlapping'.
|
||||||
|
!!! error TS2322: Object literal may only specify known properties, and 'third' does not exist in type '{ a: 1; b: 1; first: string; }'.
|
||||||
|
|
||||||
// Freshness disappears after spreading a union
|
// Freshness disappears after spreading a union
|
||||||
declare let t0: { a: any, b: any } | { d: any, e: any }
|
declare let t0: { a: any, b: any } | { d: any, e: any }
|
||||||
|
|
|
@ -46,7 +46,7 @@ type Overlapping =
|
||||||
| { b: 3, third: string }
|
| { b: 3, third: string }
|
||||||
let over: Overlapping
|
let over: Overlapping
|
||||||
|
|
||||||
// these two are not reported because there are two discriminant properties
|
// 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", second: "error" }
|
||||||
over = { a: 1, b: 1, first: "ok", third: "error" }
|
over = { a: 1, b: 1, first: "ok", third: "error" }
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ amb = { tag: "A", y: 12, extra: 12 };
|
||||||
amb = { tag: "A" };
|
amb = { tag: "A" };
|
||||||
amb = { tag: "A", z: true };
|
amb = { tag: "A", z: true };
|
||||||
var over;
|
var over;
|
||||||
// these two are not reported because there are two discriminant properties
|
// 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", second: "error" };
|
||||||
over = { a: 1, b: 1, first: "ok", third: "error" };
|
over = { a: 1, b: 1, first: "ok", third: "error" };
|
||||||
var t2 = __assign({}, t1);
|
var t2 = __assign({}, t1);
|
||||||
|
|
|
@ -127,7 +127,7 @@ let over: Overlapping
|
||||||
>over : Symbol(over, Decl(excessPropertyCheckWithUnions.ts, 45, 3))
|
>over : Symbol(over, Decl(excessPropertyCheckWithUnions.ts, 45, 3))
|
||||||
>Overlapping : Symbol(Overlapping, Decl(excessPropertyCheckWithUnions.ts, 39, 27))
|
>Overlapping : Symbol(Overlapping, Decl(excessPropertyCheckWithUnions.ts, 39, 27))
|
||||||
|
|
||||||
// these two are not reported because there are two discriminant properties
|
// 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", second: "error" }
|
||||||
>over : Symbol(over, Decl(excessPropertyCheckWithUnions.ts, 45, 3))
|
>over : Symbol(over, Decl(excessPropertyCheckWithUnions.ts, 45, 3))
|
||||||
>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 48, 8))
|
>a : Symbol(a, Decl(excessPropertyCheckWithUnions.ts, 48, 8))
|
||||||
|
|
|
@ -29,9 +29,9 @@ let wrong: ADT = { tag: "T", a1: "extra" }
|
||||||
>"extra" : "extra"
|
>"extra" : "extra"
|
||||||
|
|
||||||
wrong = { tag: "A", d20: 12 }
|
wrong = { tag: "A", d20: 12 }
|
||||||
>wrong = { tag: "A", d20: 12 } : { tag: "A"; d20: 12; }
|
>wrong = { tag: "A", d20: 12 } : { tag: "A"; d20: number; }
|
||||||
>wrong : ADT
|
>wrong : ADT
|
||||||
>{ tag: "A", d20: 12 } : { tag: "A"; d20: 12; }
|
>{ tag: "A", d20: 12 } : { tag: "A"; d20: number; }
|
||||||
>tag : string
|
>tag : string
|
||||||
>"A" : "A"
|
>"A" : "A"
|
||||||
>d20 : number
|
>d20 : number
|
||||||
|
@ -167,7 +167,7 @@ let over: Overlapping
|
||||||
>over : Overlapping
|
>over : Overlapping
|
||||||
>Overlapping : Overlapping
|
>Overlapping : Overlapping
|
||||||
|
|
||||||
// these two are not reported because there are two discriminant properties
|
// 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", second: "error" }
|
||||||
>over = { a: 1, b: 1, first: "ok", second: "error" } : { a: 1; b: 1; first: string; second: string; }
|
>over = { a: 1, b: 1, first: "ok", second: "error" } : { a: 1; b: 1; first: string; second: string; }
|
||||||
>over : Overlapping
|
>over : Overlapping
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
// @noImplicitAny: true
|
||||||
|
type ADT = {
|
||||||
|
kind: "a",
|
||||||
|
method(x: string): number;
|
||||||
|
} | {
|
||||||
|
kind: "b",
|
||||||
|
method(x: number): string;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function invoke(item: ADT) {
|
||||||
|
if (item.kind === "a") {
|
||||||
|
item.method("");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.method(42);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invoke({
|
||||||
|
kind: "a",
|
||||||
|
method(a) {
|
||||||
|
return +a;
|
||||||
|
}
|
||||||
|
});
|
|
@ -46,7 +46,7 @@ type Overlapping =
|
||||||
| { b: 3, third: string }
|
| { b: 3, third: string }
|
||||||
let over: Overlapping
|
let over: Overlapping
|
||||||
|
|
||||||
// these two are not reported because there are two discriminant properties
|
// 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", second: "error" }
|
||||||
over = { a: 1, b: 1, first: "ok", third: "error" }
|
over = { a: 1, b: 1, first: "ok", third: "error" }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue