@@ -11866,11 +11866,11 @@ namespace ts {
11866
11866
}
11867
11867
11868
11868
/**
11869
- * Get attributes symbol of the given Jsx opening-like element. The result is from resolving "attributes" property of the opening-like element.
11869
+ * Get attributes type of the given Jsx opening-like element. The result is from resolving "attributes" property of the opening-like element.
11870
11870
* @param openingLikeElement a Jsx opening-like element
11871
- * @return a symbol table resulted from resolving "attributes" property or undefined if any of the attribute resolved to any or there is no attributes.
11871
+ * @return an anonymous type (similar to the one returned by checkObjectLiteral) in which its properties are attributes property .
11872
11872
*/
11873
- function getJsxAttributeSymbolsFromJsxOpeningLikeElement (openingLikeElement: JsxOpeningLikeElement): Symbol[] | undefined {
11873
+ function createJsxAttributesTypeFromAttributesProperty (openingLikeElement: JsxOpeningLikeElement, filter?:(symbol: Symbol)=>boolean) {
11874
11874
const attributes = openingLikeElement.attributes;
11875
11875
let attributesTable = createMap<Symbol>();
11876
11876
let spread: Type = emptyObjectType;
@@ -11903,10 +11903,10 @@ namespace ts {
11903
11903
const exprType = checkExpression(attributeDecl.expression);
11904
11904
if (!(exprType.flags & (TypeFlags.Object | TypeFlags.Any))) {
11905
11905
error(attributeDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types);
11906
- return undefined ;
11906
+ return anyType ;
11907
11907
}
11908
11908
if (isTypeAny(exprType)) {
11909
- return undefined ;
11909
+ return anyType ;
11910
11910
}
11911
11911
spread = getSpreadType(spread, exprType);
11912
11912
}
@@ -11921,38 +11921,38 @@ namespace ts {
11921
11921
attributesArray = getPropertiesOfType(spread);
11922
11922
}
11923
11923
11924
- return attributesArray;
11925
- }
11924
+ attributesTable = createMap<Symbol>();
11925
+ if (attributesArray) {
11926
+ forEach(attributesArray, (attr) => {
11927
+ if (!filter || (filter && filter(attr))) {
11928
+ attributesTable[attr.name] = attr;
11929
+ }
11930
+ });
11931
+ }
11932
+ return createJsxAttributesType(attributes.symbol, attributesTable);
11926
11933
11927
- /**
11928
- * Create anonymous type from given attributes symbol table.
11929
- * @param symbol a symbol of JsxAttributes containing attributes corresponding to attributesTable
11930
- * @param attributesTable a symbol table of attributes property
11931
- */
11932
- function createJsxAttributesType(symbol: Symbol, attributesTable: Map<Symbol>) {
11933
- const result = createAnonymousType(symbol, attributesTable, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined);
11934
- const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
11935
- result.flags |= TypeFlags.JsxAttributes | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag;
11936
- result.objectFlags |= ObjectFlags.ObjectLiteral;
11937
- return result;
11934
+ /**
11935
+ * Create anonymous type from given attributes symbol table.
11936
+ * @param symbol a symbol of JsxAttributes containing attributes corresponding to attributesTable
11937
+ * @param attributesTable a symbol table of attributes property
11938
+ */
11939
+ function createJsxAttributesType(symbol: Symbol, attributesTable: Map<Symbol>) {
11940
+ const result = createAnonymousType(symbol, attributesTable, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined);
11941
+ const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
11942
+ result.flags |= TypeFlags.JsxAttributes | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag;
11943
+ result.objectFlags |= ObjectFlags.ObjectLiteral;
11944
+ return result;
11945
+ }
11938
11946
}
11939
11947
11940
11948
/**
11941
- * Check JSXAttributes. This function is used when we are trying to figure out call signature for JSX opening-like element.
11942
- * In "checkApplicableSignatureForJsxOpeningLikeElement", we get type of arguments by checking the JSX opening-like element attributes property with contextual type.
11949
+ * Check JSXAttributes from "attributes" property. This function is used when we are trying to figure out call signature for JSX opening-like element during chooseOverload
11950
+ * In "checkApplicableSignatureForJsxOpeningLikeElement", we get type of arguments for potential stateless function by checking
11951
+ * the JSX opening-like element attributes property with contextual type.
11943
11952
* @param node a JSXAttributes to be resolved of its type
11944
11953
*/
11945
11954
function checkJsxAttributes(node: JsxAttributes) {
11946
- const symbolArray = getJsxAttributeSymbolsFromJsxOpeningLikeElement(node.parent as JsxOpeningLikeElement);
11947
- let argAttributesType = anyType as Type;
11948
- if (symbolArray) {
11949
- const symbolTable = createMap<Symbol>();
11950
- forEach(symbolArray, (attr) => {
11951
- symbolTable.set(attr.name, attr);
11952
- });
11953
- argAttributesType = createJsxAttributesType(node.symbol, symbolTable);
11954
- }
11955
- return argAttributesType;
11955
+ return createJsxAttributesTypeFromAttributesProperty(node.parent as JsxOpeningLikeElement);
11956
11956
}
11957
11957
11958
11958
/**
@@ -11962,33 +11962,28 @@ namespace ts {
11962
11962
* @param openingLikeElement an opening-like JSX element to check its JSXAttributes
11963
11963
*/
11964
11964
function checkJsxAttributesAssignableToTagnameAttributes(openingLikeElement: JsxOpeningLikeElement) {
11965
+ // The function involves following steps:
11966
+ // 1. Figure out expected attributes type expected by resolving tag-name of the JSX opening-like element, tagetAttributesType.
11967
+ // During these steps, we will try to resolve the tag-name as intrinsic name, stateless function, stateful component (in the order)
11968
+ // 2. Solved Jsx attributes type given by users, sourceAttributesType, which is by resolving "attributes" property of the JSX opening-like element.
11969
+ // 3. Check if the two are assignable to each other
11970
+
11965
11971
// targetAttributesType is a type of an attributes from resolving tag-name of an opening-like JSX element.
11966
11972
const targetAttributesType = isJsxIntrinsicIdentifier(openingLikeElement.tagName) ?
11967
11973
getIntrinsicAttributesTypeFromJsxOpeningLikeElement(openingLikeElement) :
11968
11974
getCustomJsxElementAttributesType(openingLikeElement, /*shouldIncludeAllStatelessAttributesType*/ false);
11969
11975
11970
- const symbolArray = getJsxAttributeSymbolsFromJsxOpeningLikeElement(openingLikeElement);
11971
11976
// sourceAttributesType is a type of an attributes properties.
11972
11977
// i.e <div attr1={10} attr2="string" />
11973
11978
// attr1 and attr2 are treated as JSXAttributes attached in the JsxOpeningLikeElement as "attributes". They resolved to be sourceAttributesType.
11974
- let sourceAttributesType = anyType as Type;
11975
- let isSourceAttributesTypeEmpty = true;
11976
- if (symbolArray) {
11977
- // Filter out any hyphenated names as those do not play any role in type-checking unless there are corresponding properties in the target type
11978
- const symbolTable = createMap<Symbol>();
11979
- forEach(symbolArray, (attr) => {
11980
- if (isUnhyphenatedJsxName(attr.name) || getPropertyOfType(targetAttributesType, attr.name)) {
11981
- symbolTable.set(attr.name, attr);
11982
- isSourceAttributesTypeEmpty = false;
11983
- }
11979
+ const sourceAttributesType = createJsxAttributesTypeFromAttributesProperty(openingLikeElement,
11980
+ (attribute: Symbol) => {
11981
+ return isUnhyphenatedJsxName(attribute.name) || !!(getPropertyOfType(targetAttributesType, attribute.name));
11984
11982
});
11985
11983
11986
- sourceAttributesType = createJsxAttributesType(openingLikeElement.attributes.symbol, symbolTable);
11987
- }
11988
-
11989
11984
// If the targetAttributesType is an emptyObjectType, indicating that there is no property named 'props' on this instance type.
11990
11985
// but there exists a sourceAttributesType, we need to explicitly give an error as normal assignability check allow excess properties and will pass.
11991
- if (targetAttributesType === emptyObjectType && ! isTypeAny(sourceAttributesType) && !isSourceAttributesTypeEmpty ) {
11986
+ if (targetAttributesType === emptyObjectType && ( isTypeAny(sourceAttributesType) || (<ResolvedType>sourceAttributesType).properties.length > 0) ) {
11992
11987
error(openingLikeElement, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, getJsxElementPropertiesName());
11993
11988
}
11994
11989
else {
0 commit comments