@@ -141,9 +141,6 @@ namespace ts {
141
141
let globalRegExpType: ObjectType;
142
142
let globalTemplateStringsArrayType: ObjectType;
143
143
let globalESSymbolType: ObjectType;
144
- let jsxElementType: ObjectType;
145
- /** Lazily loaded, use getJsxIntrinsicElementType() */
146
- let jsxIntrinsicElementsType: ObjectType;
147
144
let globalIterableType: GenericType;
148
145
let globalIteratorType: GenericType;
149
146
let globalIterableIteratorType: GenericType;
@@ -208,12 +205,17 @@ namespace ts {
208
205
}
209
206
};
210
207
208
+ let jsxElementType: ObjectType;
209
+ /** Things we lazy load from the JSX namespace */
210
+ const jsxTypes: Map<ObjectType> = {};
211
211
const JsxNames = {
212
212
JSX: "JSX",
213
213
IntrinsicElements: "IntrinsicElements",
214
214
ElementClass: "ElementClass",
215
215
ElementAttributesPropertyNameContainer: "ElementAttributesProperty",
216
- Element: "Element"
216
+ Element: "Element",
217
+ IntrinsicAttributes: "IntrinsicAttributes",
218
+ IntrinsicClassAttributes: "IntrinsicClassAttributes"
217
219
};
218
220
219
221
const subtypeRelation: Map<RelationComparisonResult> = {};
@@ -7868,12 +7870,11 @@ namespace ts {
7868
7870
return type;
7869
7871
}
7870
7872
7871
- /// Returns the type JSX.IntrinsicElements. May return `unknownType` if that type is not present.
7872
- function getJsxIntrinsicElementsType() {
7873
- if (!jsxIntrinsicElementsType) {
7874
- jsxIntrinsicElementsType = getExportedTypeFromNamespace(JsxNames.JSX, JsxNames.IntrinsicElements) || unknownType;
7873
+ function getJsxType(name: string) {
7874
+ if (jsxTypes[name] === undefined) {
7875
+ return jsxTypes[name] = getExportedTypeFromNamespace(JsxNames.JSX, name) || unknownType;
7875
7876
}
7876
- return jsxIntrinsicElementsType ;
7877
+ return jsxTypes[name] ;
7877
7878
}
7878
7879
7879
7880
/// Given a JSX opening element or self-closing element, return the symbol of the property that the tag name points to if
@@ -7896,7 +7897,7 @@ namespace ts {
7896
7897
return links.resolvedSymbol;
7897
7898
7898
7899
function lookupIntrinsicTag(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
7899
- const intrinsicElementsType = getJsxIntrinsicElementsType( );
7900
+ const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements );
7900
7901
if (intrinsicElementsType !== unknownType) {
7901
7902
// Property case
7902
7903
const intrinsicProp = getPropertyOfType(intrinsicElementsType, (<Identifier>node.tagName).text);
@@ -7928,7 +7929,7 @@ namespace ts {
7928
7929
7929
7930
// Look up the value in the current scope
7930
7931
if (valueSymbol && valueSymbol !== unknownSymbol) {
7931
- links.jsxFlags |= JsxFlags.ClassElement ;
7932
+ links.jsxFlags |= JsxFlags.ValueElement ;
7932
7933
if (valueSymbol.flags & SymbolFlags.Alias) {
7933
7934
markAliasSymbolAsReferenced(valueSymbol);
7934
7935
}
@@ -7957,7 +7958,7 @@ namespace ts {
7957
7958
function getJsxElementInstanceType(node: JsxOpeningLikeElement) {
7958
7959
// There is no such thing as an instance type for a non-class element. This
7959
7960
// line shouldn't be hit.
7960
- Debug.assert(!!(getNodeLinks(node).jsxFlags & JsxFlags.ClassElement ), "Should not call getJsxElementInstanceType on non-class Element");
7961
+ Debug.assert(!!(getNodeLinks(node).jsxFlags & JsxFlags.ValueElement ), "Should not call getJsxElementInstanceType on non-class Element");
7961
7962
7962
7963
const classSymbol = getJsxElementTagSymbol(node);
7963
7964
if (classSymbol === unknownSymbol) {
@@ -7984,15 +7985,7 @@ namespace ts {
7984
7985
}
7985
7986
}
7986
7987
7987
- const returnType = getUnionType(signatures.map(getReturnTypeOfSignature));
7988
-
7989
- // Issue an error if this return type isn't assignable to JSX.ElementClass
7990
- const elemClassType = getJsxGlobalElementClassType();
7991
- if (elemClassType) {
7992
- checkTypeRelatedTo(returnType, elemClassType, assignableRelation, node, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements);
7993
- }
7994
-
7995
- return returnType;
7988
+ return getUnionType(signatures.map(getReturnTypeOfSignature));
7996
7989
}
7997
7990
7998
7991
/// e.g. "props" for React.d.ts,
@@ -8041,9 +8034,31 @@ namespace ts {
8041
8034
if (!links.resolvedJsxType) {
8042
8035
const sym = getJsxElementTagSymbol(node);
8043
8036
8044
- if (links.jsxFlags & JsxFlags.ClassElement) {
8037
+ if (links.jsxFlags & JsxFlags.ValueElement) {
8038
+ // Get the element instance type (the result of newing or invoking this tag)
8045
8039
const elemInstanceType = getJsxElementInstanceType(node);
8046
8040
8041
+ // Is this is a stateless function component? See if its single signature is
8042
+ // assignable to the JSX Element Type
8043
+ const callSignature = getSingleCallSignature(getTypeOfSymbol(sym));
8044
+ const callReturnType = callSignature && getReturnTypeOfSignature(callSignature);
8045
+ let paramType = callReturnType && (callSignature.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(callSignature.parameters[0]));
8046
+ if (callReturnType && isTypeAssignableTo(callReturnType, jsxElementType) && (paramType.flags & TypeFlags.ObjectType)) {
8047
+ // Intersect in JSX.IntrinsicAttributes if it exists
8048
+ const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes);
8049
+ if (intrinsicAttributes !== unknownType) {
8050
+ paramType = intersectTypes(intrinsicAttributes, paramType);
8051
+ }
8052
+ return paramType;
8053
+ }
8054
+
8055
+ // Issue an error if this return type isn't assignable to JSX.ElementClass
8056
+ const elemClassType = getJsxGlobalElementClassType();
8057
+ if (elemClassType) {
8058
+ checkTypeRelatedTo(elemInstanceType, elemClassType, assignableRelation, node, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements);
8059
+ }
8060
+
8061
+
8047
8062
if (isTypeAny(elemInstanceType)) {
8048
8063
return links.resolvedJsxType = elemInstanceType;
8049
8064
}
@@ -8065,14 +8080,36 @@ namespace ts {
8065
8080
return links.resolvedJsxType = emptyObjectType;
8066
8081
}
8067
8082
else if (isTypeAny(attributesType) || (attributesType === unknownType)) {
8083
+ // Props is of type 'any' or unknown
8068
8084
return links.resolvedJsxType = attributesType;
8069
8085
}
8070
8086
else if (!(attributesType.flags & TypeFlags.ObjectType)) {
8087
+ // Props is not an object type
8071
8088
error(node.tagName, Diagnostics.JSX_element_attributes_type_0_must_be_an_object_type, typeToString(attributesType));
8072
8089
return links.resolvedJsxType = anyType;
8073
8090
}
8074
8091
else {
8075
- return links.resolvedJsxType = attributesType;
8092
+ // Normal case -- add in IntrinsicClassElements<T> and IntrinsicElements
8093
+ let apparentAttributesType = attributesType;
8094
+ const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes);
8095
+ if (intrinsicClassAttribs !== unknownType) {
8096
+ const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol);
8097
+ if (typeParams) {
8098
+ if (typeParams.length === 1) {
8099
+ apparentAttributesType = intersectTypes(createTypeReference(<GenericType>intrinsicClassAttribs, [elemInstanceType]), apparentAttributesType);
8100
+ }
8101
+ }
8102
+ else {
8103
+ apparentAttributesType = intersectTypes(attributesType, intrinsicClassAttribs);
8104
+ }
8105
+ }
8106
+
8107
+ const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes);
8108
+ if (intrinsicAttribs !== unknownType) {
8109
+ apparentAttributesType = intersectTypes(intrinsicAttribs, apparentAttributesType);
8110
+ }
8111
+
8112
+ return links.resolvedJsxType = apparentAttributesType;
8076
8113
}
8077
8114
}
8078
8115
}
@@ -8111,7 +8148,7 @@ namespace ts {
8111
8148
8112
8149
/// Returns all the properties of the Jsx.IntrinsicElements interface
8113
8150
function getJsxIntrinsicTagNames(): Symbol[] {
8114
- const intrinsics = getJsxIntrinsicElementsType( );
8151
+ const intrinsics = getJsxType(JsxNames.IntrinsicElements );
8115
8152
return intrinsics ? getPropertiesOfType(intrinsics) : emptyArray;
8116
8153
}
8117
8154
0 commit comments