Skip to content

Commit 749bd83

Browse files
authored
Cache discriminated contextual types (#58372)
1 parent 36146aa commit 749bd83

File tree

1 file changed

+51
-41
lines changed

1 file changed

+51
-41
lines changed

src/compiler/checker.ts

+51-41
Original file line numberDiff line numberDiff line change
@@ -30789,57 +30789,67 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3078930789
}
3079030790

3079130791
function discriminateContextualTypeByObjectMembers(node: ObjectLiteralExpression, contextualType: UnionType) {
30792-
return getMatchingUnionConstituentForObjectLiteral(contextualType, node) || discriminateTypeByDiscriminableItems(
30793-
contextualType,
30794-
concatenate(
30795-
map(
30796-
filter(node.properties, (p): p is PropertyAssignment | ShorthandPropertyAssignment => {
30797-
if (!p.symbol) {
30792+
const key = `D${getNodeId(node)},${getTypeId(contextualType)}`;
30793+
return getCachedType(key) ?? setCachedType(
30794+
key,
30795+
getMatchingUnionConstituentForObjectLiteral(contextualType, node) ?? discriminateTypeByDiscriminableItems(
30796+
contextualType,
30797+
concatenate(
30798+
map(
30799+
filter(node.properties, (p): p is PropertyAssignment | ShorthandPropertyAssignment => {
30800+
if (!p.symbol) {
30801+
return false;
30802+
}
30803+
if (p.kind === SyntaxKind.PropertyAssignment) {
30804+
return isPossiblyDiscriminantValue(p.initializer) && isDiscriminantProperty(contextualType, p.symbol.escapedName);
30805+
}
30806+
if (p.kind === SyntaxKind.ShorthandPropertyAssignment) {
30807+
return isDiscriminantProperty(contextualType, p.symbol.escapedName);
30808+
}
3079830809
return false;
30799-
}
30800-
if (p.kind === SyntaxKind.PropertyAssignment) {
30801-
return isPossiblyDiscriminantValue(p.initializer) && isDiscriminantProperty(contextualType, p.symbol.escapedName);
30802-
}
30803-
if (p.kind === SyntaxKind.ShorthandPropertyAssignment) {
30804-
return isDiscriminantProperty(contextualType, p.symbol.escapedName);
30805-
}
30806-
return false;
30807-
}),
30808-
prop => ([() => getContextFreeTypeOfExpression(prop.kind === SyntaxKind.PropertyAssignment ? prop.initializer : prop.name), prop.symbol.escapedName] as const),
30809-
),
30810-
map(
30811-
filter(getPropertiesOfType(contextualType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)),
30812-
s => [() => undefinedType, s.escapedName] as const,
30810+
}),
30811+
prop => ([() => getContextFreeTypeOfExpression(prop.kind === SyntaxKind.PropertyAssignment ? prop.initializer : prop.name), prop.symbol.escapedName] as const),
30812+
),
30813+
map(
30814+
filter(getPropertiesOfType(contextualType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)),
30815+
s => [() => undefinedType, s.escapedName] as const,
30816+
),
3081330817
),
30818+
isTypeAssignableTo,
3081430819
),
30815-
isTypeAssignableTo,
3081630820
);
3081730821
}
3081830822

3081930823
function discriminateContextualTypeByJSXAttributes(node: JsxAttributes, contextualType: UnionType) {
30824+
const key = `D${getNodeId(node)},${getTypeId(contextualType)}`;
30825+
const cached = getCachedType(key);
30826+
if (cached) return cached;
3082030827
const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node));
30821-
return discriminateTypeByDiscriminableItems(
30822-
contextualType,
30823-
concatenate(
30824-
map(
30825-
filter(node.properties, p => !!p.symbol && p.kind === SyntaxKind.JsxAttribute && isDiscriminantProperty(contextualType, p.symbol.escapedName) && (!p.initializer || isPossiblyDiscriminantValue(p.initializer))),
30826-
prop => ([!(prop as JsxAttribute).initializer ? (() => trueType) : (() => getContextFreeTypeOfExpression((prop as JsxAttribute).initializer!)), prop.symbol.escapedName] as const),
30827-
),
30828-
map(
30829-
filter(getPropertiesOfType(contextualType), s => {
30830-
if (!(s.flags & SymbolFlags.Optional) || !node?.symbol?.members) {
30831-
return false;
30832-
}
30833-
const element = node.parent.parent;
30834-
if (s.escapedName === jsxChildrenPropertyName && isJsxElement(element) && getSemanticJsxChildren(element.children).length) {
30835-
return false;
30836-
}
30837-
return !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName);
30838-
}),
30839-
s => [() => undefinedType, s.escapedName] as const,
30828+
return setCachedType(
30829+
key,
30830+
discriminateTypeByDiscriminableItems(
30831+
contextualType,
30832+
concatenate(
30833+
map(
30834+
filter(node.properties, p => !!p.symbol && p.kind === SyntaxKind.JsxAttribute && isDiscriminantProperty(contextualType, p.symbol.escapedName) && (!p.initializer || isPossiblyDiscriminantValue(p.initializer))),
30835+
prop => ([!(prop as JsxAttribute).initializer ? (() => trueType) : (() => getContextFreeTypeOfExpression((prop as JsxAttribute).initializer!)), prop.symbol.escapedName] as const),
30836+
),
30837+
map(
30838+
filter(getPropertiesOfType(contextualType), s => {
30839+
if (!(s.flags & SymbolFlags.Optional) || !node?.symbol?.members) {
30840+
return false;
30841+
}
30842+
const element = node.parent.parent;
30843+
if (s.escapedName === jsxChildrenPropertyName && isJsxElement(element) && getSemanticJsxChildren(element.children).length) {
30844+
return false;
30845+
}
30846+
return !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName);
30847+
}),
30848+
s => [() => undefinedType, s.escapedName] as const,
30849+
),
3084030850
),
30851+
isTypeAssignableTo,
3084130852
),
30842-
isTypeAssignableTo,
3084330853
);
3084430854
}
3084530855

0 commit comments

Comments
 (0)