mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
Add base constraint completions for JSX attributes (#35803)
* Add base constraint completions for JSX attributes * Add test for class components
This commit is contained in:
parent
d66e959a74
commit
bed7c89354
@ -21213,14 +21213,14 @@ namespace ts {
|
||||
function getContextualTypeForArgumentAtIndex(callTarget: CallLikeExpression, argIndex: number, contextFlags?: ContextFlags): Type {
|
||||
// If we're already in the process of resolving the given signature, don't resolve again as
|
||||
// that could cause infinite recursion. Instead, return anySignature.
|
||||
const signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(callTarget);
|
||||
let signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(callTarget);
|
||||
if (contextFlags && contextFlags & ContextFlags.BaseConstraint && signature.target && !hasTypeArguments(callTarget)) {
|
||||
signature = getBaseSignature(signature.target);
|
||||
}
|
||||
|
||||
if (isJsxOpeningLikeElement(callTarget) && argIndex === 0) {
|
||||
return getEffectiveFirstArgumentForJsxSignature(signature, callTarget);
|
||||
}
|
||||
if (contextFlags && contextFlags & ContextFlags.BaseConstraint && signature.target && !hasTypeArguments(callTarget)) {
|
||||
const baseSignature = getBaseSignature(signature.target);
|
||||
return getTypeAtPosition(baseSignature, argIndex);
|
||||
}
|
||||
return getTypeAtPosition(signature, argIndex);
|
||||
}
|
||||
|
||||
@ -21645,7 +21645,7 @@ namespace ts {
|
||||
return getContextualTypeForJsxAttribute(<JsxAttribute | JsxSpreadAttribute>parent);
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
return getContextualJsxElementAttributesType(<JsxOpeningLikeElement>parent);
|
||||
return getContextualJsxElementAttributesType(<JsxOpeningLikeElement>parent, contextFlags);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@ -21655,18 +21655,20 @@ namespace ts {
|
||||
return ancestor && ancestor.inferenceContext!;
|
||||
}
|
||||
|
||||
function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement) {
|
||||
if (isJsxOpeningElement(node) && node.parent.contextualType) {
|
||||
function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags?: ContextFlags) {
|
||||
if (isJsxOpeningElement(node) && node.parent.contextualType && contextFlags !== ContextFlags.BaseConstraint) {
|
||||
// Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit
|
||||
// _However_ to hit them from the _attributes_ we must look for them here; otherwise we'll used the declared type
|
||||
// (as below) instead!
|
||||
return node.parent.contextualType;
|
||||
}
|
||||
return getContextualTypeForArgumentAtIndex(node, 0);
|
||||
return getContextualTypeForArgumentAtIndex(node, 0, contextFlags);
|
||||
}
|
||||
|
||||
function getEffectiveFirstArgumentForJsxSignature(signature: Signature, node: JsxOpeningLikeElement) {
|
||||
return getJsxReferenceKind(node) !== JsxReferenceKind.Component ? getJsxPropsTypeFromCallSignature(signature, node) : getJsxPropsTypeFromClassType(signature, node);
|
||||
return getJsxReferenceKind(node) !== JsxReferenceKind.Component
|
||||
? getJsxPropsTypeFromCallSignature(signature, node)
|
||||
: getJsxPropsTypeFromClassType(signature, node);
|
||||
}
|
||||
|
||||
function getJsxPropsTypeFromCallSignature(sig: Signature, context: JsxOpeningLikeElement) {
|
||||
|
||||
@ -1279,7 +1279,8 @@ namespace ts.Completions {
|
||||
// Cursor is inside a JSX self-closing element or opening element
|
||||
const attrsType = jsxContainer && typeChecker.getContextualType(jsxContainer.attributes);
|
||||
if (!attrsType) return GlobalsSearch.Continue;
|
||||
symbols = filterJsxAttributes(getPropertiesForObjectExpression(attrsType, /*baseType*/ undefined, jsxContainer!.attributes, typeChecker), jsxContainer!.attributes.properties);
|
||||
const baseType = jsxContainer && typeChecker.getContextualType(jsxContainer.attributes, ContextFlags.BaseConstraint);
|
||||
symbols = filterJsxAttributes(getPropertiesForObjectExpression(attrsType, baseType, jsxContainer!.attributes, typeChecker), jsxContainer!.attributes.properties);
|
||||
setSortTextToOptionalMember();
|
||||
completionKind = CompletionKind.MemberLike;
|
||||
isNewIdentifierLocation = false;
|
||||
|
||||
34
tests/cases/fourslash/completionsJsxAttributeGeneric2.ts
Normal file
34
tests/cases/fourslash/completionsJsxAttributeGeneric2.ts
Normal file
@ -0,0 +1,34 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @jsx: preserve
|
||||
|
||||
// @Filename: index.tsx
|
||||
////declare namespace JSX {
|
||||
//// interface Element {}
|
||||
//// interface IntrinsicElements {}
|
||||
//// interface ElementAttributesProperty { props }
|
||||
////}
|
||||
////
|
||||
////type Props = { a?: string, b?: string };
|
||||
////function Component<T extends Props>(props: T) { return null; }
|
||||
////const e1 = <Component /*1*/ />;
|
||||
////const e2 = <Component /*2*/></Component>
|
||||
////
|
||||
////declare class Component2<T extends Props> {
|
||||
//// props: T;
|
||||
////}
|
||||
////const e3 = <Component2 /*3*/ />;
|
||||
////const e4 = <Component2 /*4*/></Component2>;
|
||||
|
||||
["1", "2", "3", "4"].forEach(marker => {
|
||||
verify.completions({
|
||||
marker,
|
||||
exact: [{
|
||||
name: "a",
|
||||
sortText: completion.SortText.OptionalMember
|
||||
}, {
|
||||
name: "b",
|
||||
sortText: completion.SortText.OptionalMember
|
||||
}]
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user