@@ -16567,6 +16567,9 @@ namespace ts {
16567
16567
// If we're already in the process of resolving the given signature, don't resolve again as
16568
16568
// that could cause infinite recursion. Instead, return anySignature.
16569
16569
const signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(callTarget);
16570
+ if (isJsxOpeningLikeElement(callTarget) && argIndex === 0) {
16571
+ return getEffectiveFirstArgumentForJsxSignature(signature, callTarget);
16572
+ }
16570
16573
return getTypeAtPosition(signature, argIndex);
16571
16574
}
16572
16575
@@ -16934,7 +16937,11 @@ namespace ts {
16934
16937
// (as below) instead!
16935
16938
return node.parent.contextualType;
16936
16939
}
16937
- return getAttributesTypeFromJsxOpeningLikeElement(node);
16940
+ return getContextualTypeForArgumentAtIndex(node, 0);
16941
+ }
16942
+
16943
+ function getEffectiveFirstArgumentForJsxSignature(signature: Signature, node: JsxOpeningLikeElement) {
16944
+ return isJsxStatelessFunctionReference(node) ? getJsxPropsTypeFromCallSignature(signature, node) : getJsxPropsTypeFromClassType(signature, node);
16938
16945
}
16939
16946
16940
16947
function getJsxPropsTypeFromCallSignature(sig: Signature, context: JsxOpeningLikeElement) {
@@ -16952,23 +16959,42 @@ namespace ts {
16952
16959
return isTypeAny(instanceType) ? instanceType : getTypeOfPropertyOfType(instanceType, forcedLookupLocation);
16953
16960
}
16954
16961
16962
+ function getStaticTypeOfReferencedJsxConstructor(context: JsxOpeningLikeElement) {
16963
+ if (isJsxIntrinsicIdentifier(context.tagName)) {
16964
+ const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(context);
16965
+ const fakeSignature = createSignatureForJSXIntrinsic(context, result);
16966
+ return getOrCreateTypeFromSignature(fakeSignature);
16967
+ }
16968
+ const tagType = checkExpressionCached(context.tagName);
16969
+ if (tagType.flags & TypeFlags.StringLiteral) {
16970
+ const result = getIntrinsicAttributesTypeFromStringLiteralType(tagType as StringLiteralType, context);
16971
+ if (!result) {
16972
+ return errorType;
16973
+ }
16974
+ const fakeSignature = createSignatureForJSXIntrinsic(context, result);
16975
+ return getOrCreateTypeFromSignature(fakeSignature);
16976
+ }
16977
+ return tagType;
16978
+ }
16979
+
16955
16980
function getJsxManagedAttributesFromLocatedAttributes(context: JsxOpeningLikeElement, ns: Symbol, attributesType: Type) {
16956
16981
const managedSym = getJsxLibraryManagedAttributes(ns);
16957
16982
if (managedSym) {
16958
16983
const declaredManagedType = getDeclaredTypeOfSymbol(managedSym);
16984
+ const ctorType = getStaticTypeOfReferencedJsxConstructor(context);
16959
16985
if (length((declaredManagedType as GenericType).typeParameters) >= 2) {
16960
- const args = fillMissingTypeArguments([checkExpressionCached(context.tagName) , attributesType], (declaredManagedType as GenericType).typeParameters, 2, isInJSFile(context));
16986
+ const args = fillMissingTypeArguments([ctorType , attributesType], (declaredManagedType as GenericType).typeParameters, 2, isInJSFile(context));
16961
16987
return createTypeReference((declaredManagedType as GenericType), args);
16962
16988
}
16963
16989
else if (length(declaredManagedType.aliasTypeArguments) >= 2) {
16964
- const args = fillMissingTypeArguments([checkExpressionCached(context.tagName) , attributesType], declaredManagedType.aliasTypeArguments!, 2, isInJSFile(context));
16990
+ const args = fillMissingTypeArguments([ctorType , attributesType], declaredManagedType.aliasTypeArguments!, 2, isInJSFile(context));
16965
16991
return getTypeAliasInstantiation(declaredManagedType.aliasSymbol!, args);
16966
16992
}
16967
16993
}
16968
16994
return attributesType;
16969
16995
}
16970
16996
16971
- function getJsxPropsTypeFromClassType(sig: Signature, isJs: boolean, context: JsxOpeningLikeElement) {
16997
+ function getJsxPropsTypeFromClassType(sig: Signature, context: JsxOpeningLikeElement) {
16972
16998
const ns = getJsxNamespaceAt(context);
16973
16999
const forcedLookupLocation = getJsxElementPropertiesName(ns);
16974
17000
let attributesType = forcedLookupLocation === undefined
@@ -17003,7 +17029,7 @@ namespace ts {
17003
17029
const hostClassType = getReturnTypeOfSignature(sig);
17004
17030
apparentAttributesType = intersectTypes(
17005
17031
typeParams
17006
- ? createTypeReference(<GenericType>intrinsicClassAttribs, fillMissingTypeArguments([hostClassType], typeParams, getMinTypeArgumentCount(typeParams), isJs ))
17032
+ ? createTypeReference(<GenericType>intrinsicClassAttribs, fillMissingTypeArguments([hostClassType], typeParams, getMinTypeArgumentCount(typeParams), isInJSFile(context) ))
17007
17033
: intrinsicClassAttribs,
17008
17034
apparentAttributesType
17009
17035
);
@@ -17843,50 +17869,6 @@ namespace ts {
17843
17869
return anyType;
17844
17870
}
17845
17871
17846
- /**
17847
- * Resolve attributes type of the given opening-like element. The attributes type is a type of attributes associated with the given elementType.
17848
- * For instance:
17849
- * declare function Foo(attr: { p1: string}): JSX.Element;
17850
- * <Foo p1={10} />; // This function will try resolve "Foo" and return an attributes type of "Foo" which is "{ p1: string }"
17851
- *
17852
- * The function is intended to initially be called from getAttributesTypeFromJsxOpeningLikeElement which already handle JSX-intrinsic-element..
17853
- * This function will try to resolve custom JSX attributes type in following order: string literal, stateless function, and stateful component
17854
- *
17855
- * @param openingLikeElement a non-intrinsic JSXOPeningLikeElement
17856
- * @param elementType an instance type of the given opening-like element. If undefined, the function will check type openinglikeElement's tagname.
17857
- * @return attributes type if able to resolve the type of node
17858
- * anyType if there is no type ElementAttributesProperty or there is an error
17859
- * emptyObjectType if there is no "prop" in the element instance type
17860
- */
17861
- function resolveCustomJsxElementAttributesType(openingLikeElement: JsxOpeningLikeElement, elementType: Type): Type {
17862
- if (elementType.flags & TypeFlags.Union) {
17863
- const types = (elementType as UnionType).types;
17864
- return getUnionType(types.map(type => {
17865
- return resolveCustomJsxElementAttributesType(openingLikeElement, type);
17866
- }), UnionReduction.Subtype);
17867
- }
17868
-
17869
- // Shortcircuit any
17870
- if (isTypeAny(elementType)) {
17871
- return elementType;
17872
- }
17873
- // If the elemType is a string type, we have to return anyType to prevent an error downstream as we will try to find construct or call signature of the type
17874
- else if (elementType.flags & TypeFlags.String) {
17875
- return anyType;
17876
- }
17877
- else if (elementType.flags & TypeFlags.StringLiteral) {
17878
- return getIntrinsicAttributesTypeFromStringLiteralType(elementType as StringLiteralType, openingLikeElement) || anyType;
17879
- }
17880
-
17881
- // Get the element instance type (the result of newing or invoking this tag)
17882
- const preferedOverload = getNodeLinks(openingLikeElement).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(openingLikeElement);
17883
- if (!preferedOverload) {
17884
- return errorType;
17885
- }
17886
- const isSFC = !length(getSignaturesOfType(elementType, SignatureKind.Construct));
17887
- return isSFC ? getJsxPropsTypeFromCallSignature(preferedOverload, openingLikeElement) : getJsxPropsTypeFromClassType(preferedOverload, isInJSFile(openingLikeElement), openingLikeElement);
17888
- }
17889
-
17890
17872
function checkJsxReturnAssignableToAppropriateBound(isSFC: boolean, elemInstanceType: Type, openingLikeElement: Node) {
17891
17873
if (isSFC) {
17892
17874
const sfcReturnConstraint = getJsxStatelessElementTypeAt(openingLikeElement);
@@ -17926,29 +17908,6 @@ namespace ts {
17926
17908
return links.resolvedJsxElementAttributesType;
17927
17909
}
17928
17910
17929
- /**
17930
- * Get attributes type of the given custom opening-like JSX element.
17931
- * This function is intended to be called from a caller that handles intrinsic JSX element already.
17932
- * @param node a custom JSX opening-like element
17933
- */
17934
- function getCustomJsxElementAttributesType(node: JsxOpeningLikeElement): Type {
17935
- return resolveCustomJsxElementAttributesType(node, checkExpression(node.tagName));
17936
- }
17937
-
17938
- /**
17939
- * Get the attributes type, which indicates the attributes that are valid on the given JSXOpeningLikeElement.
17940
- * @param node a JSXOpeningLikeElement node
17941
- * @return an attributes type of the given node
17942
- */
17943
- function getAttributesTypeFromJsxOpeningLikeElement(node: JsxOpeningLikeElement): Type {
17944
- if (isJsxIntrinsicIdentifier(node.tagName)) {
17945
- return getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node);
17946
- }
17947
- else {
17948
- return getCustomJsxElementAttributesType(node);
17949
- }
17950
- }
17951
-
17952
17911
function getJsxElementClassTypeAt(location: Node): Type | undefined {
17953
17912
const type = getJsxType(JsxNames.ElementClass, location);
17954
17913
if (type === errorType) return undefined;
@@ -18900,8 +18859,7 @@ namespace ts {
18900
18859
}
18901
18860
18902
18861
function inferJsxTypeArguments(node: JsxOpeningLikeElement, signature: Signature, excludeArgument: ReadonlyArray<boolean> | undefined, context: InferenceContext): Type[] {
18903
- const isCtor = !!length(getSignaturesOfType(checkExpression(node.tagName), SignatureKind.Construct));
18904
- const paramType = isCtor ? getJsxPropsTypeFromClassType(signature, isInJSFile(node), node) : getJsxPropsTypeFromCallSignature(signature, node);
18862
+ const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node);
18905
18863
18906
18864
const checkAttrType = checkExpressionWithContextualType(node.attributes, paramType, excludeArgument && excludeArgument[0] !== undefined ? identityMapper : context);
18907
18865
inferTypes(context.inferences, checkAttrType, paramType);
@@ -19046,7 +19004,7 @@ namespace ts {
19046
19004
19047
19005
function isJsxStatelessFunctionReference(node: JsxOpeningLikeElement) {
19048
19006
if (isJsxIntrinsicIdentifier(node.tagName)) {
19049
- return false ;
19007
+ return true ;
19050
19008
}
19051
19009
const tagType = checkExpression(node.tagName);
19052
19010
return !length(getSignaturesOfType(getApparentType(tagType), SignatureKind.Construct));
@@ -19059,11 +19017,11 @@ namespace ts {
19059
19017
* @param relation a relationship to check parameter and argument type
19060
19018
* @param excludeArgument
19061
19019
*/
19062
- function checkApplicableSignatureForJsxOpeningLikeElement(node: JsxOpeningLikeElement, signature: Signature, isCtor: boolean, relation: Map<RelationComparisonResult>, reportErrors: boolean) {
19020
+ function checkApplicableSignatureForJsxOpeningLikeElement(node: JsxOpeningLikeElement, signature: Signature, relation: Map<RelationComparisonResult>, reportErrors: boolean) {
19063
19021
// Stateless function components can have maximum of three arguments: "props", "context", and "updater".
19064
19022
// However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props,
19065
19023
// can be specified by users through attributes property.
19066
- const paramType = isCtor ? getJsxPropsTypeFromClassType(signature, isInJSFile(node), node) : getJsxPropsTypeFromCallSignature (signature, node);
19024
+ const paramType = getEffectiveFirstArgumentForJsxSignature (signature, node);
19067
19025
const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*contextualMapper*/ undefined);
19068
19026
return checkTypeRelatedToAndOptionallyElaborate(attributesType, paramType, relation, reportErrors ? node.tagName : undefined, node.attributes);
19069
19027
}
@@ -19076,7 +19034,7 @@ namespace ts {
19076
19034
excludeArgument: boolean[] | undefined,
19077
19035
reportErrors: boolean) {
19078
19036
if (isJsxOpeningLikeElement(node)) {
19079
- return checkApplicableSignatureForJsxOpeningLikeElement(node, signature, !isJsxStatelessFunctionReference(node), relation, reportErrors);
19037
+ return checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, reportErrors);
19080
19038
}
19081
19039
const thisType = getThisTypeOfSignature(signature);
19082
19040
if (thisType && thisType !== voidType && node.kind !== SyntaxKind.NewExpression) {
@@ -20000,33 +19958,63 @@ namespace ts {
20000
19958
return resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp, headMessage);
20001
19959
}
20002
19960
19961
+ function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature {
19962
+ // TODO: Since this builds some nodes for the fake'd up signature, this might be worth caching on the node
19963
+ const namespace = getJsxNamespaceAt(node);
19964
+ const exports = namespace && getExportsOfSymbol(namespace);
19965
+ // TODO: We fake up a SFC signature for each intrinsic, however a more specific per-element signature drawn from the JSX declaration
19966
+ // file would probably be preferable.
19967
+ const typeSymbol = exports && getSymbol(exports, JsxNames.Element, SymbolFlags.Type);
19968
+ const returnNode = typeSymbol && nodeBuilder.symbolToEntityName(typeSymbol, SymbolFlags.Type, node);
19969
+ const declaration = createFunctionTypeNode(/*typeParameters*/ undefined,
19970
+ [createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotdotdot*/ undefined, "props", /*questionMark*/ undefined, nodeBuilder.typeToTypeNode(result, node))],
19971
+ returnNode ? createTypeReferenceNode(returnNode, /*typeArguments*/ undefined) : createKeywordTypeNode(SyntaxKind.AnyKeyword)
19972
+ );
19973
+ const parameterSymbol = createSymbol(SymbolFlags.FunctionScopedVariable, "props" as __String);
19974
+ parameterSymbol.type = result;
19975
+ return createSignature(
19976
+ declaration,
19977
+ /*typeParameters*/ undefined,
19978
+ /*thisParameter*/ undefined,
19979
+ [parameterSymbol],
19980
+ typeSymbol ? getDeclaredTypeOfSymbol(typeSymbol) : errorType,
19981
+ /*returnTypePredicate*/ undefined,
19982
+ 1,
19983
+ /*hasRestparameter*/ false,
19984
+ /*hasLiteralTypes*/ false
19985
+ );
19986
+ }
19987
+
20003
19988
function resolveJsxOpeningLikeElement(node: JsxOpeningLikeElement, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature {
20004
19989
if (isJsxIntrinsicIdentifier(node.tagName)) {
20005
19990
const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node);
20006
- checkTypeAssignableToAndOptionallyElaborate(checkExpressionCached(node.attributes, CheckMode.Normal), result, node.tagName, node.attributes);
20007
- return anySignature; // TODO: Fake up a signature from the intrinsic types
19991
+ const fakeSignature = createSignatureForJSXIntrinsic(node, result);
19992
+ checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*mapper*/ undefined), result, node.tagName, node.attributes);
19993
+ return fakeSignature;
20008
19994
}
20009
19995
const exprTypes = checkExpression(node.tagName);
20010
19996
const apparentType = getApparentType(exprTypes);
20011
19997
if (apparentType === errorType) {
20012
19998
return resolveErrorCall(node);
20013
19999
}
20014
20000
20015
- const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
20016
- const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
20017
- if (isUntypedFunctionCall(exprTypes, apparentType, callSignatures.length, constructSignatures.length) || exprTypes.flags & TypeFlags.String) {
20018
- return resolveUntypedCall(node);
20019
- }
20020
-
20021
20001
if (exprTypes.flags & TypeFlags.StringLiteral) {
20022
20002
const intrinsicType = getIntrinsicAttributesTypeFromStringLiteralType(exprTypes as StringLiteralType, node);
20023
20003
if (!intrinsicType) {
20024
20004
error(node, Diagnostics.Property_0_does_not_exist_on_type_1, (exprTypes as StringLiteralType).value, "JSX." + JsxNames.IntrinsicElements);
20005
+ return resolveUntypedCall(node);
20025
20006
}
20026
20007
else {
20027
- checkTypeAssignableToAndOptionallyElaborate(checkExpressionCached(node.attributes, CheckMode.Normal), intrinsicType, node.tagName, node.attributes);
20008
+ const fakeSignature = createSignatureForJSXIntrinsic(node, intrinsicType);
20009
+ checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*mapper*/ undefined), intrinsicType, node.tagName, node.attributes);
20010
+ return fakeSignature;
20028
20011
}
20029
- return anySignature; // TODO: Fake up a signature from the intrinsic types
20012
+ }
20013
+
20014
+ const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
20015
+ const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
20016
+ if (exprTypes.flags & TypeFlags.String || isUntypedFunctionCall(exprTypes, apparentType, callSignatures.length, constructSignatures.length)) {
20017
+ return resolveUntypedCall(node);
20030
20018
}
20031
20019
20032
20020
const signatures = getUninstantiatedJsxSignaturesOfType(apparentType);
0 commit comments