@@ -6868,9 +6868,14 @@ namespace ts {
6868
6868
// Use this property as the error node as this will be more helpful in
6869
6869
// reasoning about what went wrong.
6870
6870
Debug.assert(!!errorNode);
6871
- errorNode = prop.valueDeclaration;
6872
- reportError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1,
6873
- symbolToString(prop), typeToString(target));
6871
+ if (isJsxAttributes(errorNode)) {
6872
+ reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(prop), typeToString(target));
6873
+ }
6874
+ else {
6875
+ errorNode = prop.valueDeclaration;
6876
+ reportError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1,
6877
+ symbolToString(prop), typeToString(target));
6878
+ }
6874
6879
}
6875
6880
return true;
6876
6881
}
@@ -10700,18 +10705,17 @@ namespace ts {
10700
10705
function isJsxAttribute(node: Node): node is JsxAttribute {
10701
10706
return node.kind === SyntaxKind.JsxAttribute;
10702
10707
}
10708
+
10703
10709
/**
10704
- * Resolee the type of attributes in the given attributes in opening-like element.
10705
- * Unlike "getJsxElementAttributesType" which get type of attributes type from
10706
- * resolving jsxopeningLikeElement's tagName
10710
+ * Get attributes symbol of the given Jsx opening-like element. The result is from resolving " attributes" property of the opening-like element.
10711
+ * @param openingLikeElement a Jsx opening-like element
10712
+ * @return a symbol table resulted from resolving "attributes" property or undefined if any of the attribute resolved to any or there is no attributes.
10707
10713
*/
10708
- function resolvedJsxAttributesTypeFromOpeningLikeElement(openingLikeElement: JsxOpeningLikeElement) {
10714
+ function getAttributesSymbolTableOfJsxOpeningLikeElement(openingLikeElement: JsxOpeningElement): Map<Symbol> | undefined {
10715
+ const attributes = openingLikeElement.attributes;
10709
10716
let attributesTable = createMap<Symbol>();
10710
- let attributesArray: Symbol[] = [];
10711
10717
const spreads: SpreadElementType[] = [];
10712
-
10713
- const attributes = openingLikeElement.attributes;
10714
-
10718
+ let attributesArray: Symbol[] = [];
10715
10719
for (const attributeDecl of attributes.properties) {
10716
10720
const member = attributeDecl.symbol;
10717
10721
if (isJsxAttribute(attributeDecl)) {
@@ -10732,25 +10736,29 @@ namespace ts {
10732
10736
}
10733
10737
attributeSymbol.type = exprType;
10734
10738
attributeSymbol.target = member;
10735
- attributesTable[member .name] = member ;
10736
- attributesArray.push(member );
10739
+ attributesTable[attributeSymbol .name] = attributeSymbol ;
10740
+ attributesArray.push(attributeSymbol );
10737
10741
}
10738
10742
else {
10739
10743
Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute);
10740
10744
if (attributesArray.length > 0) {
10741
- const t = createObjectLiteralType( ) as SpreadElementType;
10745
+ const t = createJsxAttributesType(attributes, attributesTable ) as SpreadElementType;
10742
10746
t.isDeclaredProperty = true;
10743
10747
spreads.push(t);
10744
10748
attributesArray = [];
10745
10749
attributesTable = createMap<Symbol>();
10746
10750
}
10747
- spreads.push(checkExpression(attributeDecl.expression) as SpreadElementType);
10751
+ const exprType = checkExpression(attributeDecl.expression);
10752
+ if (isTypeAny(exprType)) {
10753
+ return undefined;
10754
+ }
10755
+ spreads.push(exprType as SpreadElementType);
10748
10756
}
10749
10757
}
10750
10758
10751
10759
if (spreads.length > 0) {
10752
10760
if (attributesArray.length > 0) {
10753
- const t = createObjectLiteralType( ) as SpreadElementType;
10761
+ const t = createJsxAttributesType(attributes, attributesTable ) as SpreadElementType;
10754
10762
t.isDeclaredProperty = true;
10755
10763
spreads.push(t);
10756
10764
}
@@ -10764,13 +10772,47 @@ namespace ts {
10764
10772
})
10765
10773
}
10766
10774
10767
- return createObjectLiteralType();
10768
- function createObjectLiteralType() {
10769
- const result = createAnonymousType(attributes.symbol, attributesTable, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined);
10770
- const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
10771
- result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag;
10772
- return result;
10775
+ return attributesTable;
10776
+ }
10777
+
10778
+ /**
10779
+ * Create ananoymous type from given attributes symbol table.
10780
+ * @param jsxAttributes a JsxAttributes node containing attributes in attributesTable
10781
+ * @param attributesTable a symbol table of attributes property
10782
+ */
10783
+ function createJsxAttributesType(jsxAttributes: JsxAttributes, attributesTable: Map<Symbol>) {
10784
+ const result = createAnonymousType(jsxAttributes.symbol, attributesTable, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined);
10785
+ const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
10786
+ result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag;
10787
+ return result;
10788
+ }
10789
+
10790
+ function resolveCustomJsxElementAttributesTypeFromOpeningLikeElement(openingLikeElement: JsxOpeningLikeElement) {
10791
+ const symbolTable = getAttributesSymbolTableOfJsxOpeningLikeElement(openingLikeElement);
10792
+ return createJsxAttributesType(openingLikeElement.attributes, symbolTable);
10793
+ }
10794
+
10795
+ /**
10796
+ * Check attributes type of intrinsic JSx opening-like element.
10797
+ * The function is intended to be called from checkJsxAttributes which has already check the the opening-like element is an intrinsic element.
10798
+ * @param openingLikeElement an intrinsic Jsx opening-like element
10799
+ */
10800
+ function checkAttributesTypeOfIntrinsicJsxOpeningLikeElement(openingLikeElement: JsxOpeningLikeElement) {
10801
+ const targetAttributesType = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(openingLikeElement);
10802
+ const symbolTable = getAttributesSymbolTableOfJsxOpeningLikeElement(openingLikeElement);
10803
+ // Filter out any hyphenated names as those are not play any role in type-checking unless there are corresponding properties in the target type
10804
+ let attributesTable: Map<Symbol>;
10805
+ let sourceAttributesType = anyType as Type;
10806
+ if (symbolTable) {
10807
+ attributesTable = createMap<Symbol>();
10808
+ for (const key in symbolTable) {
10809
+ if (isUnhyphenatedJsxName(key) || getPropertyOfType(targetAttributesType, key)) {
10810
+ attributesTable[key] = symbolTable[key];
10811
+ }
10812
+ }
10813
+ sourceAttributesType = createJsxAttributesType(openingLikeElement.attributes, attributesTable);
10773
10814
}
10815
+ checkTypeAssignableTo(sourceAttributesType, targetAttributesType, openingLikeElement.attributes.properties.length > 0 ? openingLikeElement.attributes : openingLikeElement);
10774
10816
}
10775
10817
10776
10818
/**
@@ -10781,36 +10823,41 @@ namespace ts {
10781
10823
function checkJsxAttributes(openingLikeElement: JsxOpeningLikeElement) {
10782
10824
// Get target attributes type from resolving opening-element
10783
10825
// Check if given attributes (openingLikeELement.attributes) are compatible with the given attributes
10784
- const targetAttributesType = getAttributesTypeFromJsxOpeningLikeElement(openingLikeElement);
10785
- const sourceAttribtuesType = resolvedJsxAttributesTypeFromOpeningLikeElement(openingLikeElement);
10786
- const nameTable = createMap<boolean>();
10787
- // Process this array in right-to-left order so we know which
10788
- // attributes (mostly from spreads) are being overwritten and
10789
- // thus should have their types ignored
10790
- let sawSpreadedAny = false;
10791
- const attributes = openingLikeElement.attributes.properties;
10792
- for (let i = attributes.length - 1; i >= 0; i--) {
10793
- if (attributes[i].kind === SyntaxKind.JsxAttribute) {
10794
- checkJsxAttribute(<JsxAttribute>(attributes[i]), targetAttributesType, nameTable);
10795
- }
10796
- else {
10797
- Debug.assert(attributes[i].kind === SyntaxKind.JsxSpreadAttribute);
10798
- const spreadType = checkJsxSpreadAttribute(<JsxSpreadAttribute>(attributes[i]), targetAttributesType, nameTable);
10799
- if (isTypeAny(spreadType)) {
10800
- sawSpreadedAny = true;
10826
+ if (isJsxIntrinsicIdentifier(openingLikeElement.tagName)) {
10827
+ checkAttributesTypeOfIntrinsicJsxOpeningLikeElement(openingLikeElement);
10828
+ }
10829
+ else {
10830
+ const targetAttributesType = getAttributesTypeFromJsxOpeningLikeElement(openingLikeElement);
10831
+ const sourceAttribtuesType = resolveCustomJsxElementAttributesTypeFromOpeningLikeElement(openingLikeElement);
10832
+ const nameTable = createMap<boolean>();
10833
+ // Process this array in right-to-left order so we know which
10834
+ // attributes (mostly from spreads) are being overwritten and
10835
+ // thus should have their types ignored
10836
+ let sawSpreadedAny = false;
10837
+ const attributes = openingLikeElement.attributes.properties;
10838
+ for (let i = attributes.length - 1; i >= 0; i--) {
10839
+ if (attributes[i].kind === SyntaxKind.JsxAttribute) {
10840
+ checkJsxAttribute(<JsxAttribute>(attributes[i]), targetAttributesType, nameTable);
10841
+ }
10842
+ else {
10843
+ Debug.assert(attributes[i].kind === SyntaxKind.JsxSpreadAttribute);
10844
+ const spreadType = checkJsxSpreadAttribute(<JsxSpreadAttribute>(attributes[i]), targetAttributesType, nameTable);
10845
+ if (isTypeAny(spreadType)) {
10846
+ sawSpreadedAny = true;
10847
+ }
10801
10848
}
10802
10849
}
10803
- }
10804
10850
10805
- // Check that all required properties have been provided. If an 'any'
10806
- // was spreaded in, though, assume that it provided all required properties
10807
- if (targetAttributesType && !sawSpreadedAny) {
10808
- const targetProperties = getPropertiesOfType(targetAttributesType);
10809
- for (let i = 0; i < targetProperties.length; i++) {
10810
- if (!(targetProperties[i].flags & SymbolFlags.Optional) &&
10811
- !nameTable[targetProperties[i].name]) {
10851
+ // Check that all required properties have been provided. If an 'any'
10852
+ // was spreaded in, though, assume that it provided all required properties
10853
+ if (targetAttributesType && !sawSpreadedAny) {
10854
+ const targetProperties = getPropertiesOfType(targetAttributesType);
10855
+ for (let i = 0; i < targetProperties.length; i++) {
10856
+ if (!(targetProperties[i].flags & SymbolFlags.Optional) &&
10857
+ !nameTable[targetProperties[i].name]) {
10812
10858
10813
- error(openingLikeElement, Diagnostics.Property_0_is_missing_in_type_1, targetProperties[i].name, typeToString(targetAttributesType));
10859
+ error(openingLikeElement, Diagnostics.Property_0_is_missing_in_type_1, targetProperties[i].name, typeToString(targetAttributesType));
10860
+ }
10814
10861
}
10815
10862
}
10816
10863
}
@@ -20390,6 +20437,7 @@ namespace ts {
20390
20437
20391
20438
function checkGrammarJsxElement(node: JsxOpeningLikeElement) {
20392
20439
const seen = createMap<boolean>();
20440
+
20393
20441
for (const attr of node.attributes.properties) {
20394
20442
if (attr.kind === SyntaxKind.JsxSpreadAttribute) {
20395
20443
continue;
0 commit comments