Skip to content

Commit 8863e2f

Browse files
authored
Discriminate contextual types using shorthand properties (#55151)
1 parent defb504 commit 8863e2f

File tree

5 files changed

+80
-6
lines changed

5 files changed

+80
-6
lines changed

src/compiler/checker.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22785,7 +22785,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2278522785
findMostOverlappyType(source, target);
2278622786
}
2278722787

22788-
function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary) {
22788+
function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: (readonly [() => Type, __String])[], related: (source: Type, target: Type) => boolean | Ternary) {
2278922789
const types = target.types;
2279022790
const include: Ternary[] = types.map(t => t.flags & TypeFlags.Primitive ? Ternary.False : Ternary.True);
2279122791
for (const [getDiscriminatingType, propertyName] of discriminators) {
@@ -29438,12 +29438,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2943829438
return getMatchingUnionConstituentForObjectLiteral(contextualType, node) || discriminateTypeByDiscriminableItems(contextualType,
2943929439
concatenate(
2944029440
map(
29441-
filter(node.properties, p => !!p.symbol && p.kind === SyntaxKind.PropertyAssignment && isPossiblyDiscriminantValue(p.initializer) && isDiscriminantProperty(contextualType, p.symbol.escapedName)),
29442-
prop => ([() => getContextFreeTypeOfExpression((prop as PropertyAssignment).initializer), prop.symbol.escapedName] as [() => Type, __String])
29441+
filter(node.properties, (p): p is PropertyAssignment | ShorthandPropertyAssignment => {
29442+
if (!p.symbol) {
29443+
return false;
29444+
}
29445+
if (p.kind === SyntaxKind.PropertyAssignment) {
29446+
return isPossiblyDiscriminantValue(p.initializer) && isDiscriminantProperty(contextualType, p.symbol.escapedName);
29447+
}
29448+
if (p.kind === SyntaxKind.ShorthandPropertyAssignment) {
29449+
return isDiscriminantProperty(contextualType, p.symbol.escapedName);
29450+
}
29451+
return false;
29452+
}),
29453+
prop => ([() => getContextFreeTypeOfExpression(prop.kind === SyntaxKind.PropertyAssignment ? prop.initializer : prop.name), prop.symbol.escapedName] as const)
2944329454
),
2944429455
map(
2944529456
filter(getPropertiesOfType(contextualType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)),
29446-
s => [() => undefinedType, s.escapedName] as [() => Type, __String]
29457+
s => [() => undefinedType, s.escapedName] as const
2944729458
)
2944829459
),
2944929460
isTypeAssignableTo
@@ -29456,7 +29467,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2945629467
concatenate(
2945729468
map(
2945829469
filter(node.properties, p => !!p.symbol && p.kind === SyntaxKind.JsxAttribute && isDiscriminantProperty(contextualType, p.symbol.escapedName) && (!p.initializer || isPossiblyDiscriminantValue(p.initializer))),
29459-
prop => ([!(prop as JsxAttribute).initializer ? (() => trueType) : (() => getContextFreeTypeOfExpression((prop as JsxAttribute).initializer!)), prop.symbol.escapedName] as [() => Type, __String])
29470+
prop => ([!(prop as JsxAttribute).initializer ? (() => trueType) : (() => getContextFreeTypeOfExpression((prop as JsxAttribute).initializer!)), prop.symbol.escapedName] as const)
2946029471
),
2946129472
map(
2946229473
filter(getPropertiesOfType(contextualType), s => {
@@ -29469,7 +29480,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2946929480
}
2947029481
return !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName);
2947129482
}),
29472-
s => [() => undefinedType, s.escapedName] as [() => Type, __String]
29483+
s => [() => undefinedType, s.escapedName] as const
2947329484
)
2947429485
),
2947529486
isTypeAssignableTo

tests/baselines/reference/contextuallyTypedByDiscriminableUnion.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ invoke({
2525
return +a;
2626
}
2727
});
28+
29+
const kind = "a"
30+
invoke({
31+
kind,
32+
method(a) {
33+
return +a;
34+
}
35+
})
2836

2937

3038
//// [contextuallyTypedByDiscriminableUnion.js]
@@ -42,3 +50,10 @@ invoke({
4250
return +a;
4351
}
4452
});
53+
var kind = "a";
54+
invoke({
55+
kind: kind,
56+
method: function (a) {
57+
return +a;
58+
}
59+
});

tests/baselines/reference/contextuallyTypedByDiscriminableUnion.symbols

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,21 @@ invoke({
6060
}
6161
});
6262

63+
const kind = "a"
64+
>kind : Symbol(kind, Decl(contextuallyTypedByDiscriminableUnion.ts, 25, 5))
65+
66+
invoke({
67+
>invoke : Symbol(invoke, Decl(contextuallyTypedByDiscriminableUnion.ts, 6, 2))
68+
69+
kind,
70+
>kind : Symbol(kind, Decl(contextuallyTypedByDiscriminableUnion.ts, 26, 8))
71+
72+
method(a) {
73+
>method : Symbol(method, Decl(contextuallyTypedByDiscriminableUnion.ts, 27, 9))
74+
>a : Symbol(a, Decl(contextuallyTypedByDiscriminableUnion.ts, 28, 11))
75+
76+
return +a;
77+
>a : Symbol(a, Decl(contextuallyTypedByDiscriminableUnion.ts, 28, 11))
78+
}
79+
})
80+

tests/baselines/reference/contextuallyTypedByDiscriminableUnion.types

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,25 @@ invoke({
6969
}
7070
});
7171

72+
const kind = "a"
73+
>kind : "a"
74+
>"a" : "a"
75+
76+
invoke({
77+
>invoke({ kind, method(a) { return +a; }}) : void
78+
>invoke : (item: ADT) => void
79+
>{ kind, method(a) { return +a; }} : { kind: "a"; method(a: string): number; }
80+
81+
kind,
82+
>kind : "a"
83+
84+
method(a) {
85+
>method : (a: string) => number
86+
>a : string
87+
88+
return +a;
89+
>+a : number
90+
>a : string
91+
}
92+
})
93+

tests/cases/compiler/contextuallyTypedByDiscriminableUnion.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,11 @@ invoke({
2323
return +a;
2424
}
2525
});
26+
27+
const kind = "a"
28+
invoke({
29+
kind,
30+
method(a) {
31+
return +a;
32+
}
33+
})

0 commit comments

Comments
 (0)