mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-23 10:29:01 -06:00
add jsx fragments to callLikeExpression (#59933)
This commit is contained in:
parent
bd3d70058c
commit
f6d2e73c5a
@ -637,7 +637,9 @@ import {
|
||||
isJsxAttribute,
|
||||
isJsxAttributeLike,
|
||||
isJsxAttributes,
|
||||
isJsxCallLike,
|
||||
isJsxElement,
|
||||
isJsxFragment,
|
||||
isJsxNamespacedName,
|
||||
isJsxOpeningElement,
|
||||
isJsxOpeningFragment,
|
||||
@ -828,6 +830,7 @@ import {
|
||||
JsxAttributeName,
|
||||
JsxAttributes,
|
||||
JsxAttributeValue,
|
||||
JsxCallLike,
|
||||
JsxChild,
|
||||
JsxClosingElement,
|
||||
JsxElement,
|
||||
@ -2121,6 +2124,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
var emptyObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
|
||||
var emptyJsxObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
|
||||
emptyJsxObjectType.objectFlags |= ObjectFlags.JsxAttributes;
|
||||
var emptyFreshJsxObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
|
||||
emptyFreshJsxObjectType.objectFlags |= ObjectFlags.JsxAttributes | ObjectFlags.FreshLiteral | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral;
|
||||
|
||||
var emptyTypeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type);
|
||||
emptyTypeLiteralSymbol.members = createSymbolTable();
|
||||
@ -32453,13 +32458,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return getContextualTypeForArgumentAtIndex(node, 0);
|
||||
}
|
||||
|
||||
function getEffectiveFirstArgumentForJsxSignature(signature: Signature, node: JsxOpeningLikeElement) {
|
||||
return getJsxReferenceKind(node) !== JsxReferenceKind.Component
|
||||
function getEffectiveFirstArgumentForJsxSignature(signature: Signature, node: JsxCallLike) {
|
||||
return isJsxOpeningFragment(node) || getJsxReferenceKind(node) !== JsxReferenceKind.Component
|
||||
? getJsxPropsTypeFromCallSignature(signature, node)
|
||||
: getJsxPropsTypeFromClassType(signature, node);
|
||||
}
|
||||
|
||||
function getJsxPropsTypeFromCallSignature(sig: Signature, context: JsxOpeningLikeElement) {
|
||||
function getJsxPropsTypeFromCallSignature(sig: Signature, context: JsxCallLike) {
|
||||
let propsType = getTypeOfFirstParameterOfSignatureWithFallback(sig, unknownType);
|
||||
propsType = getJsxManagedAttributesFromLocatedAttributes(context, getJsxNamespaceAt(context), propsType);
|
||||
const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context);
|
||||
@ -32494,7 +32499,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return isTypeAny(instanceType) ? instanceType : getTypeOfPropertyOfType(instanceType, forcedLookupLocation);
|
||||
}
|
||||
|
||||
function getStaticTypeOfReferencedJsxConstructor(context: JsxOpeningLikeElement) {
|
||||
function getStaticTypeOfReferencedJsxConstructor(context: JsxCallLike) {
|
||||
if (isJsxOpeningFragment(context)) return getJSXFragmentType(context);
|
||||
if (isJsxIntrinsicTagName(context.tagName)) {
|
||||
const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(context);
|
||||
const fakeSignature = createSignatureForJSXIntrinsic(context, result);
|
||||
@ -32512,7 +32518,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return tagType;
|
||||
}
|
||||
|
||||
function getJsxManagedAttributesFromLocatedAttributes(context: JsxOpeningLikeElement, ns: Symbol, attributesType: Type) {
|
||||
function getJsxManagedAttributesFromLocatedAttributes(context: JsxCallLike, ns: Symbol, attributesType: Type) {
|
||||
const managedSym = getJsxLibraryManagedAttributes(ns);
|
||||
if (managedSym) {
|
||||
const ctorType = getStaticTypeOfReferencedJsxConstructor(context);
|
||||
@ -33303,9 +33309,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
* @remarks Because this function calls getSpreadType, it needs to use the same checks as checkObjectLiteral,
|
||||
* which also calls getSpreadType.
|
||||
*/
|
||||
function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, checkMode: CheckMode = CheckMode.Normal) {
|
||||
const attributes = openingLikeElement.attributes;
|
||||
const contextualType = getContextualType(attributes, ContextFlags.None);
|
||||
function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxCallLike, checkMode: CheckMode = CheckMode.Normal) {
|
||||
const allAttributesTable = strictNullChecks ? createSymbolTable() : undefined;
|
||||
let attributesTable = createSymbolTable();
|
||||
let spread: Type = emptyJsxObjectType;
|
||||
@ -33315,71 +33319,84 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
let objectFlags: ObjectFlags = ObjectFlags.JsxAttributes;
|
||||
const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(openingLikeElement));
|
||||
|
||||
for (const attributeDecl of attributes.properties) {
|
||||
const member = attributeDecl.symbol;
|
||||
if (isJsxAttribute(attributeDecl)) {
|
||||
const exprType = checkJsxAttribute(attributeDecl, checkMode);
|
||||
objectFlags |= getObjectFlags(exprType) & ObjectFlags.PropagatingFlags;
|
||||
const isJsxOpenFragment = isJsxOpeningFragment(openingLikeElement);
|
||||
|
||||
const attributeSymbol = createSymbol(SymbolFlags.Property | member.flags, member.escapedName);
|
||||
attributeSymbol.declarations = member.declarations;
|
||||
attributeSymbol.parent = member.parent;
|
||||
if (member.valueDeclaration) {
|
||||
attributeSymbol.valueDeclaration = member.valueDeclaration;
|
||||
}
|
||||
attributeSymbol.links.type = exprType;
|
||||
attributeSymbol.links.target = member;
|
||||
attributesTable.set(attributeSymbol.escapedName, attributeSymbol);
|
||||
allAttributesTable?.set(attributeSymbol.escapedName, attributeSymbol);
|
||||
if (getEscapedTextOfJsxAttributeName(attributeDecl.name) === jsxChildrenPropertyName) {
|
||||
explicitlySpecifyChildrenAttribute = true;
|
||||
}
|
||||
if (contextualType) {
|
||||
const prop = getPropertyOfType(contextualType, member.escapedName);
|
||||
if (prop && prop.declarations && isDeprecatedSymbol(prop) && isIdentifier(attributeDecl.name)) {
|
||||
addDeprecatedSuggestion(attributeDecl.name, prop.declarations, attributeDecl.name.escapedText as string);
|
||||
let attributesSymbol: Symbol | undefined;
|
||||
let attributeParent: Node = openingLikeElement;
|
||||
if (!isJsxOpenFragment) {
|
||||
const attributes = openingLikeElement.attributes;
|
||||
attributesSymbol = attributes.symbol;
|
||||
attributeParent = attributes;
|
||||
const contextualType = getContextualType(attributes, ContextFlags.None);
|
||||
for (const attributeDecl of attributes.properties) {
|
||||
const member = attributeDecl.symbol;
|
||||
if (isJsxAttribute(attributeDecl)) {
|
||||
const exprType = checkJsxAttribute(attributeDecl, checkMode);
|
||||
objectFlags |= getObjectFlags(exprType) & ObjectFlags.PropagatingFlags;
|
||||
|
||||
const attributeSymbol = createSymbol(SymbolFlags.Property | member.flags, member.escapedName);
|
||||
attributeSymbol.declarations = member.declarations;
|
||||
attributeSymbol.parent = member.parent;
|
||||
if (member.valueDeclaration) {
|
||||
attributeSymbol.valueDeclaration = member.valueDeclaration;
|
||||
}
|
||||
}
|
||||
if (contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(attributeDecl)) {
|
||||
const inferenceContext = getInferenceContext(attributes);
|
||||
Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context
|
||||
const inferenceNode = (attributeDecl.initializer as JsxExpression).expression!;
|
||||
addIntraExpressionInferenceSite(inferenceContext, inferenceNode, exprType);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute);
|
||||
if (attributesTable.size > 0) {
|
||||
spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false);
|
||||
attributesTable = createSymbolTable();
|
||||
}
|
||||
const exprType = getReducedType(checkExpression(attributeDecl.expression, checkMode & CheckMode.Inferential));
|
||||
if (isTypeAny(exprType)) {
|
||||
hasSpreadAnyType = true;
|
||||
}
|
||||
if (isValidSpreadType(exprType)) {
|
||||
spread = getSpreadType(spread, exprType, attributes.symbol, objectFlags, /*readonly*/ false);
|
||||
if (allAttributesTable) {
|
||||
checkSpreadPropOverrides(exprType, allAttributesTable, attributeDecl);
|
||||
attributeSymbol.links.type = exprType;
|
||||
attributeSymbol.links.target = member;
|
||||
attributesTable.set(attributeSymbol.escapedName, attributeSymbol);
|
||||
allAttributesTable?.set(attributeSymbol.escapedName, attributeSymbol);
|
||||
if (getEscapedTextOfJsxAttributeName(attributeDecl.name) === jsxChildrenPropertyName) {
|
||||
explicitlySpecifyChildrenAttribute = true;
|
||||
}
|
||||
if (contextualType) {
|
||||
const prop = getPropertyOfType(contextualType, member.escapedName);
|
||||
if (prop && prop.declarations && isDeprecatedSymbol(prop) && isIdentifier(attributeDecl.name)) {
|
||||
addDeprecatedSuggestion(attributeDecl.name, prop.declarations, attributeDecl.name.escapedText as string);
|
||||
}
|
||||
}
|
||||
if (contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(attributeDecl)) {
|
||||
const inferenceContext = getInferenceContext(attributes);
|
||||
Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context
|
||||
const inferenceNode = (attributeDecl.initializer as JsxExpression).expression!;
|
||||
addIntraExpressionInferenceSite(inferenceContext, inferenceNode, exprType);
|
||||
}
|
||||
}
|
||||
else {
|
||||
error(attributeDecl.expression, Diagnostics.Spread_types_may_only_be_created_from_object_types);
|
||||
typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType;
|
||||
Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute);
|
||||
if (attributesTable.size > 0) {
|
||||
spread = getSpreadType(spread, createJsxAttributesTypeHelper(), attributes.symbol, objectFlags, /*readonly*/ false);
|
||||
attributesTable = createSymbolTable();
|
||||
}
|
||||
const exprType = getReducedType(checkExpression(attributeDecl.expression, checkMode & CheckMode.Inferential));
|
||||
if (isTypeAny(exprType)) {
|
||||
hasSpreadAnyType = true;
|
||||
}
|
||||
if (isValidSpreadType(exprType)) {
|
||||
spread = getSpreadType(spread, exprType, attributes.symbol, objectFlags, /*readonly*/ false);
|
||||
if (allAttributesTable) {
|
||||
checkSpreadPropOverrides(exprType, allAttributesTable, attributeDecl);
|
||||
}
|
||||
}
|
||||
else {
|
||||
error(attributeDecl.expression, Diagnostics.Spread_types_may_only_be_created_from_object_types);
|
||||
typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasSpreadAnyType) {
|
||||
if (attributesTable.size > 0) {
|
||||
spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false);
|
||||
if (!hasSpreadAnyType) {
|
||||
if (attributesTable.size > 0) {
|
||||
spread = getSpreadType(spread, createJsxAttributesTypeHelper(), attributes.symbol, objectFlags, /*readonly*/ false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle children attribute
|
||||
const parent = openingLikeElement.parent.kind === SyntaxKind.JsxElement ? openingLikeElement.parent as JsxElement : undefined;
|
||||
const parent = openingLikeElement.parent;
|
||||
// We have to check that openingElement of the parent is the one we are visiting as this may not be true for selfClosingElement
|
||||
if (parent && parent.openingElement === openingLikeElement && getSemanticJsxChildren(parent.children).length > 0) {
|
||||
if (
|
||||
(isJsxElement(parent) && parent.openingElement === openingLikeElement || isJsxFragment(parent) && parent.openingFragment === openingLikeElement) &&
|
||||
getSemanticJsxChildren(parent.children).length > 0
|
||||
) {
|
||||
const childrenTypes: Type[] = checkJsxChildren(parent, checkMode);
|
||||
|
||||
if (!hasSpreadAnyType && jsxChildrenPropertyName && jsxChildrenPropertyName !== "") {
|
||||
@ -33387,10 +33404,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// This is because children element will overwrite the value from attributes.
|
||||
// Note: we will not warn "children" attribute overwritten if "children" attribute is specified in object spread.
|
||||
if (explicitlySpecifyChildrenAttribute) {
|
||||
error(attributes, Diagnostics._0_are_specified_twice_The_attribute_named_0_will_be_overwritten, unescapeLeadingUnderscores(jsxChildrenPropertyName));
|
||||
error(attributeParent, Diagnostics._0_are_specified_twice_The_attribute_named_0_will_be_overwritten, unescapeLeadingUnderscores(jsxChildrenPropertyName));
|
||||
}
|
||||
|
||||
const contextualType = getApparentTypeOfContextualType(openingLikeElement.attributes, /*contextFlags*/ undefined);
|
||||
const contextualType = isJsxOpeningElement(openingLikeElement) ? getApparentTypeOfContextualType(openingLikeElement.attributes, /*contextFlags*/ undefined) : undefined;
|
||||
const childrenContextualType = contextualType && getTypeOfPropertyOfContextualType(contextualType, jsxChildrenPropertyName);
|
||||
// If there are children in the body of JSX element, create dummy attribute "children" with the union of children types so that it will pass the attribute checking process
|
||||
const childrenPropSymbol = createSymbol(SymbolFlags.Property, jsxChildrenPropertyName);
|
||||
@ -33399,11 +33416,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
createArrayType(getUnionType(childrenTypes));
|
||||
// Fake up a property declaration for the children
|
||||
childrenPropSymbol.valueDeclaration = factory.createPropertySignature(/*modifiers*/ undefined, unescapeLeadingUnderscores(jsxChildrenPropertyName), /*questionToken*/ undefined, /*type*/ undefined);
|
||||
setParent(childrenPropSymbol.valueDeclaration, attributes);
|
||||
setParent(childrenPropSymbol.valueDeclaration, attributeParent);
|
||||
childrenPropSymbol.valueDeclaration.symbol = childrenPropSymbol;
|
||||
const childPropMap = createSymbolTable();
|
||||
childPropMap.set(jsxChildrenPropertyName, childrenPropSymbol);
|
||||
spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, emptyArray), attributes.symbol, objectFlags, /*readonly*/ false);
|
||||
spread = getSpreadType(spread, createAnonymousType(attributesSymbol, childPropMap, emptyArray, emptyArray, emptyArray), attributesSymbol, objectFlags, /*readonly*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -33413,20 +33430,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (typeToIntersect && spread !== emptyJsxObjectType) {
|
||||
return getIntersectionType([typeToIntersect, spread]);
|
||||
}
|
||||
return typeToIntersect || (spread === emptyJsxObjectType ? createJsxAttributesType() : spread);
|
||||
return typeToIntersect || (spread === emptyJsxObjectType ? createJsxAttributesTypeHelper() : spread);
|
||||
|
||||
/**
|
||||
* Create anonymous type from given attributes symbol table.
|
||||
* @param symbol a symbol of JsxAttributes containing attributes corresponding to attributesTable
|
||||
* @param attributesTable a symbol table of attributes property
|
||||
*/
|
||||
function createJsxAttributesType() {
|
||||
function createJsxAttributesTypeHelper() {
|
||||
objectFlags |= ObjectFlags.FreshLiteral;
|
||||
const result = createAnonymousType(attributes.symbol, attributesTable, emptyArray, emptyArray, emptyArray);
|
||||
result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral;
|
||||
return result;
|
||||
return createJsxAttributesType(objectFlags, attributesSymbol, attributesTable);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create anonymous type from given attributes symbol table.
|
||||
* @param symbol a symbol of JsxAttributes containing attributes corresponding to attributesTable
|
||||
* @param attributesTable a symbol table of attributes property
|
||||
*/
|
||||
function createJsxAttributesType(objectFlags: ObjectFlags, attributesSymbol: Symbol | undefined, attributesTable: SymbolTable): Type {
|
||||
const result = createAnonymousType(attributesSymbol, attributesTable, emptyArray, emptyArray, emptyArray);
|
||||
result.objectFlags |= objectFlags | ObjectFlags.FreshLiteral | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral;
|
||||
return result;
|
||||
}
|
||||
|
||||
function checkJsxChildren(node: JsxElement | JsxFragment, checkMode?: CheckMode) {
|
||||
const childrenTypes: Type[] = [];
|
||||
@ -33637,7 +33657,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return getNameFromJsxElementAttributesContainer(JsxNames.ElementChildrenAttributeNameContainer, jsxNamespace);
|
||||
}
|
||||
|
||||
function getUninstantiatedJsxSignaturesOfType(elementType: Type, caller: JsxOpeningLikeElement): readonly Signature[] {
|
||||
function getUninstantiatedJsxSignaturesOfType(elementType: Type, caller: JsxCallLike): readonly Signature[] {
|
||||
if (elementType.flags & TypeFlags.String) {
|
||||
return [anySignature];
|
||||
}
|
||||
@ -33817,11 +33837,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
markJsxAliasReferenced(node);
|
||||
|
||||
const sig = getResolvedSignature(node);
|
||||
checkDeprecatedSignature(sig, node);
|
||||
|
||||
if (isNodeOpeningLikeElement) {
|
||||
const jsxOpeningLikeNode = node;
|
||||
const sig = getResolvedSignature(jsxOpeningLikeNode);
|
||||
checkDeprecatedSignature(sig, node);
|
||||
|
||||
const elementTypeConstraint = getJsxElementTypeTypeAt(jsxOpeningLikeNode);
|
||||
if (elementTypeConstraint !== undefined) {
|
||||
const tagName = jsxOpeningLikeNode.tagName;
|
||||
@ -35156,6 +35176,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function hasCorrectArity(node: CallLikeExpression, args: readonly Expression[], signature: Signature, signatureHelpTrailingComma = false) {
|
||||
if (isJsxOpeningFragment(node)) return true;
|
||||
|
||||
let argCount: number;
|
||||
let callIsIncomplete = false; // In incomplete call we want to be lenient when we have too few arguments
|
||||
let effectiveParameterCount = getParameterCount(signature);
|
||||
@ -35512,8 +35534,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
* @param signature a candidate signature we are trying whether it is a call signature
|
||||
* @param relation a relationship to check parameter and argument type
|
||||
*/
|
||||
function checkApplicableSignatureForJsxOpeningLikeElement(
|
||||
node: JsxOpeningLikeElement,
|
||||
function checkApplicableSignatureForJsxCallLikeElement(
|
||||
node: JsxCallLike,
|
||||
signature: Signature,
|
||||
relation: Map<string, RelationComparisonResult>,
|
||||
checkMode: CheckMode,
|
||||
@ -35525,14 +35547,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props,
|
||||
// can be specified by users through attributes property.
|
||||
const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node);
|
||||
const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*inferenceContext*/ undefined, checkMode);
|
||||
const attributesType = isJsxOpeningFragment(node) ? createJsxAttributesTypeFromAttributesProperty(node) : checkExpressionWithContextualType(node.attributes, paramType, /*inferenceContext*/ undefined, checkMode);
|
||||
const checkAttributesType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(attributesType) : attributesType;
|
||||
return checkTagNameDoesNotExpectTooManyArguments() && checkTypeRelatedToAndOptionallyElaborate(
|
||||
checkAttributesType,
|
||||
paramType,
|
||||
relation,
|
||||
reportErrors ? node.tagName : undefined,
|
||||
node.attributes,
|
||||
reportErrors ? isJsxOpeningFragment(node) ? node : node.tagName : undefined,
|
||||
isJsxOpeningFragment(node) ? undefined : node.attributes,
|
||||
/*headMessage*/ undefined,
|
||||
containingMessageChain,
|
||||
errorOutputContainer,
|
||||
@ -35542,6 +35564,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (getJsxNamespaceContainerForImplicitImport(node)) {
|
||||
return true; // factory is implicitly jsx/jsxdev - assume it fits the bill, since we don't strongly look for the jsx/jsxs/jsxDEV factory APIs anywhere else (at least not yet)
|
||||
}
|
||||
|
||||
// We assume fragments have the correct arity since the node does not have attributes
|
||||
const tagType = (isJsxOpeningElement(node) || isJsxSelfClosingElement(node)) && !(isJsxIntrinsicTagName(node.tagName) || isJsxNamespacedName(node.tagName)) ? checkExpression(node.tagName) : undefined;
|
||||
if (!tagType) {
|
||||
return true;
|
||||
@ -35600,10 +35624,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
if (reportErrors) {
|
||||
const diag = createDiagnosticForNode(node.tagName, Diagnostics.Tag_0_expects_at_least_1_arguments_but_the_JSX_factory_2_provides_at_most_3, entityNameToString(node.tagName), absoluteMinArgCount, entityNameToString(factory), maxParamCount);
|
||||
const tagNameDeclaration = getSymbolAtLocation(node.tagName)?.valueDeclaration;
|
||||
// We will not report errors in this function for fragments, since we do not check them in this function
|
||||
const tagName = (node as JsxOpeningElement | JsxSelfClosingElement).tagName;
|
||||
const diag = createDiagnosticForNode(tagName, Diagnostics.Tag_0_expects_at_least_1_arguments_but_the_JSX_factory_2_provides_at_most_3, entityNameToString(tagName), absoluteMinArgCount, entityNameToString(factory), maxParamCount);
|
||||
const tagNameDeclaration = getSymbolAtLocation(tagName)?.valueDeclaration;
|
||||
if (tagNameDeclaration) {
|
||||
addRelatedInfo(diag, createDiagnosticForNode(tagNameDeclaration, Diagnostics._0_is_declared_here, entityNameToString(node.tagName)));
|
||||
addRelatedInfo(diag, createDiagnosticForNode(tagNameDeclaration, Diagnostics._0_is_declared_here, entityNameToString(tagName)));
|
||||
}
|
||||
if (errorOutputContainer && errorOutputContainer.skipLogging) {
|
||||
(errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag);
|
||||
@ -35632,8 +35658,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
inferenceContext: InferenceContext | undefined,
|
||||
): readonly Diagnostic[] | undefined {
|
||||
const errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } = { errors: undefined, skipLogging: true };
|
||||
if (isJsxOpeningLikeElement(node)) {
|
||||
if (!checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, checkMode, reportErrors, containingMessageChain, errorOutputContainer)) {
|
||||
if (isJsxCallLike(node)) {
|
||||
if (!checkApplicableSignatureForJsxCallLikeElement(node, signature, relation, checkMode, reportErrors, containingMessageChain, errorOutputContainer)) {
|
||||
Debug.assert(!reportErrors || !!errorOutputContainer.errors, "jsx should have errors when reporting errors");
|
||||
return errorOutputContainer.errors || emptyArray;
|
||||
}
|
||||
@ -35736,6 +35762,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
* Returns the effective arguments for an expression that works like a function invocation.
|
||||
*/
|
||||
function getEffectiveCallArguments(node: CallLikeExpression): readonly Expression[] {
|
||||
if (isJsxOpeningFragment(node)) {
|
||||
// This attributes Type does not include a children property yet, the same way a fragment created with <React.Fragment> does not at this stage
|
||||
return [createSyntheticExpression(node, emptyFreshJsxObjectType)];
|
||||
}
|
||||
|
||||
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
const template = node.template;
|
||||
const args: Expression[] = [createSyntheticExpression(template, getGlobalTemplateStringsArrayType())];
|
||||
@ -36014,42 +36045,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
|
||||
const isDecorator = node.kind === SyntaxKind.Decorator;
|
||||
const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
|
||||
const isJsxOpenFragment = isJsxOpeningFragment(node);
|
||||
const isInstanceof = node.kind === SyntaxKind.BinaryExpression;
|
||||
const reportErrors = !isInferencePartiallyBlocked && !candidatesOutArray;
|
||||
|
||||
let typeArguments: NodeArray<TypeNode> | undefined;
|
||||
|
||||
if (!isDecorator && !isInstanceof && !isSuperCall(node)) {
|
||||
typeArguments = (node as CallExpression).typeArguments;
|
||||
|
||||
// We already perform checking on the type arguments on the class declaration itself.
|
||||
if (isTaggedTemplate || isJsxOpeningOrSelfClosingElement || (node as CallExpression).expression.kind !== SyntaxKind.SuperKeyword) {
|
||||
forEach(typeArguments, checkSourceElement);
|
||||
}
|
||||
}
|
||||
|
||||
const candidates = candidatesOutArray || [];
|
||||
// reorderCandidates fills up the candidates array directly
|
||||
reorderCandidates(signatures, candidates, callChainFlags);
|
||||
Debug.assert(candidates.length, "Revert #54442 and add a testcase with whatever triggered this");
|
||||
|
||||
const args = getEffectiveCallArguments(node);
|
||||
|
||||
// The excludeArgument array contains true for each context sensitive argument (an argument
|
||||
// is context sensitive it is susceptible to a one-time permanent contextual typing).
|
||||
//
|
||||
// The idea is that we will perform type argument inference & assignability checking once
|
||||
// without using the susceptible parameters that are functions, and once more for those
|
||||
// parameters, contextually typing each as we go along.
|
||||
//
|
||||
// For a tagged template, then the first argument be 'undefined' if necessary because it
|
||||
// represents a TemplateStringsArray.
|
||||
//
|
||||
// For a decorator, no arguments are susceptible to contextual typing due to the fact
|
||||
// decorators are applied to a declaration by the emitter, and not to an expression.
|
||||
const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters;
|
||||
let argCheckMode = !isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive) ? CheckMode.SkipContextSensitive : CheckMode.Normal;
|
||||
|
||||
// The following variables are captured and modified by calls to chooseOverload.
|
||||
// If overload resolution or type argument inference fails, we want to report the
|
||||
// best error possible. The best error is one which says that an argument was not
|
||||
@ -36075,6 +36074,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
let candidateForArgumentArityError: Signature | undefined;
|
||||
let candidateForTypeArgumentError: Signature | undefined;
|
||||
let result: Signature | undefined;
|
||||
let argCheckMode = CheckMode.Normal;
|
||||
|
||||
let candidates: Signature[] = [];
|
||||
let typeArguments: NodeArray<TypeNode> | undefined;
|
||||
if (!isDecorator && !isInstanceof && !isSuperCall(node) && !isJsxOpenFragment) {
|
||||
typeArguments = (node as CallExpression).typeArguments;
|
||||
|
||||
// We already perform checking on the type arguments on the class declaration itself.
|
||||
if (isTaggedTemplate || isJsxOpeningOrSelfClosingElement || (node as CallExpression).expression.kind !== SyntaxKind.SuperKeyword) {
|
||||
forEach(typeArguments, checkSourceElement);
|
||||
}
|
||||
}
|
||||
|
||||
candidates = candidatesOutArray || [];
|
||||
// reorderCandidates fills up the candidates array directly
|
||||
reorderCandidates(signatures, candidates, callChainFlags);
|
||||
if (!isJsxOpenFragment) {
|
||||
Debug.assert(candidates.length, "Revert #54442 and add a testcase with whatever triggered this");
|
||||
}
|
||||
const args = getEffectiveCallArguments(node);
|
||||
|
||||
// The excludeArgument array contains true for each context sensitive argument (an argument
|
||||
// is context sensitive it is susceptible to a one-time permanent contextual typing).
|
||||
//
|
||||
// The idea is that we will perform type argument inference & assignability checking once
|
||||
// without using the susceptible parameters that are functions, and once more for those
|
||||
// parameters, contextually typing each as we go along.
|
||||
//
|
||||
// For a tagged template, then the first argument be 'undefined' if necessary because it
|
||||
// represents a TemplateStringsArray.
|
||||
//
|
||||
// For a decorator, no arguments are susceptible to contextual typing due to the fact
|
||||
// decorators are applied to a declaration by the emitter, and not to an expression.
|
||||
const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters;
|
||||
if (!isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive)) {
|
||||
argCheckMode = CheckMode.SkipContextSensitive;
|
||||
}
|
||||
|
||||
// If we are in signature help, a trailing comma indicates that we intend to provide another argument,
|
||||
// so we will only accept overloads with arity at least 1 higher than the current number of provided arguments.
|
||||
@ -36199,7 +36235,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
else if (candidateForTypeArgumentError) {
|
||||
checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression | TaggedTemplateExpression | JsxOpeningLikeElement).typeArguments!, /*reportErrors*/ true, headMessage);
|
||||
}
|
||||
else {
|
||||
else if (!isJsxOpenFragment) {
|
||||
const signaturesWithCorrectTypeArgumentArity = filter(signatures, s => hasCorrectTypeArgumentArity(s, typeArguments));
|
||||
if (signaturesWithCorrectTypeArgumentArity.length === 0) {
|
||||
diagnostics.add(getTypeArgumentArityError(node, signatures, typeArguments!, headMessage));
|
||||
@ -36941,7 +36977,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None, headMessage);
|
||||
}
|
||||
|
||||
function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature {
|
||||
function createSignatureForJSXIntrinsic(node: JsxCallLike, result: Type): Signature {
|
||||
const namespace = getJsxNamespaceAt(node);
|
||||
const exports = namespace && getExportsOfSymbol(namespace);
|
||||
// We fake up a SFC signature for each intrinsic, however a more specific per-element signature drawn from the JSX declaration
|
||||
@ -36963,23 +36999,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
);
|
||||
}
|
||||
|
||||
function resolveJsxOpeningLikeElement(node: JsxOpeningLikeElement, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature {
|
||||
if (isJsxIntrinsicTagName(node.tagName)) {
|
||||
const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node);
|
||||
const fakeSignature = createSignatureForJSXIntrinsic(node, result);
|
||||
checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*inferenceContext*/ undefined, CheckMode.Normal), result, node.tagName, node.attributes);
|
||||
if (length(node.typeArguments)) {
|
||||
forEach(node.typeArguments, checkSourceElement);
|
||||
diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), node.typeArguments!, Diagnostics.Expected_0_type_arguments_but_got_1, 0, length(node.typeArguments)));
|
||||
function getJSXFragmentType(node: JsxOpeningFragment): Type {
|
||||
// An opening fragment is required in order for `getJsxNamespace` to give the fragment factory
|
||||
const sourceFileLinks = getNodeLinks(getSourceFileOfNode(node));
|
||||
if (sourceFileLinks.jsxFragmentType !== undefined) return sourceFileLinks.jsxFragmentType;
|
||||
|
||||
const jsxFragmentFactoryName = getJsxNamespace(node);
|
||||
const jsxFactoryRefErr = diagnostics ? Diagnostics.Using_JSX_fragments_requires_fragment_factory_0_to_be_in_scope_but_it_could_not_be_found : undefined;
|
||||
const jsxFactorySymbol = getJsxNamespaceContainerForImplicitImport(node) ??
|
||||
resolveName(node, jsxFragmentFactoryName, SymbolFlags.Value, /*nameNotFoundMessage*/ jsxFactoryRefErr, /*isUse*/ true);
|
||||
|
||||
if (jsxFactorySymbol === undefined) return sourceFileLinks.jsxFragmentType = errorType;
|
||||
if (jsxFactorySymbol.escapedName === ReactNames.Fragment) return sourceFileLinks.jsxFragmentType = getTypeOfSymbol(jsxFactorySymbol);
|
||||
|
||||
const resolvedAlias = (jsxFactorySymbol.flags & SymbolFlags.Alias) === 0 ? jsxFactorySymbol : resolveAlias(jsxFactorySymbol);
|
||||
const reactExports = jsxFactorySymbol && getExportsOfSymbol(resolvedAlias);
|
||||
const typeSymbol = reactExports && getSymbol(reactExports, ReactNames.Fragment, SymbolFlags.BlockScopedVariable);
|
||||
const type = typeSymbol && getTypeOfSymbol(typeSymbol);
|
||||
return sourceFileLinks.jsxFragmentType = type === undefined ? errorType : type;
|
||||
}
|
||||
|
||||
function resolveJsxOpeningLikeElement(node: JsxCallLike, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature {
|
||||
const isJsxOpenFragment = isJsxOpeningFragment(node);
|
||||
let exprTypes: Type;
|
||||
if (!isJsxOpenFragment) {
|
||||
if (isJsxIntrinsicTagName(node.tagName)) {
|
||||
const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node);
|
||||
const fakeSignature = createSignatureForJSXIntrinsic(node, result);
|
||||
checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*inferenceContext*/ undefined, CheckMode.Normal), result, node.tagName, node.attributes);
|
||||
if (length(node.typeArguments)) {
|
||||
forEach(node.typeArguments, checkSourceElement);
|
||||
diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), node.typeArguments!, Diagnostics.Expected_0_type_arguments_but_got_1, 0, length(node.typeArguments)));
|
||||
}
|
||||
return fakeSignature;
|
||||
}
|
||||
return fakeSignature;
|
||||
exprTypes = checkExpression(node.tagName);
|
||||
}
|
||||
else {
|
||||
exprTypes = getJSXFragmentType(node);
|
||||
}
|
||||
const exprTypes = checkExpression(node.tagName);
|
||||
const apparentType = getApparentType(exprTypes);
|
||||
if (isErrorType(apparentType)) {
|
||||
return resolveErrorCall(node);
|
||||
}
|
||||
|
||||
const signatures = getUninstantiatedJsxSignaturesOfType(exprTypes, node);
|
||||
if (isUntypedFunctionCall(exprTypes, apparentType, signatures.length, /*constructSignatures*/ 0)) {
|
||||
return resolveUntypedCall(node);
|
||||
@ -36987,7 +37049,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
if (signatures.length === 0) {
|
||||
// We found no signatures at all, which is an error
|
||||
error(node.tagName, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(node.tagName));
|
||||
if (isJsxOpenFragment) {
|
||||
error(node, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(node));
|
||||
}
|
||||
else {
|
||||
error(node.tagName, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(node.tagName));
|
||||
}
|
||||
return resolveErrorCall(node);
|
||||
}
|
||||
|
||||
@ -37049,6 +37116,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return resolveTaggedTemplateExpression(node, candidatesOutArray, checkMode);
|
||||
case SyntaxKind.Decorator:
|
||||
return resolveDecorator(node, candidatesOutArray, checkMode);
|
||||
case SyntaxKind.JsxOpeningFragment:
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
return resolveJsxOpeningLikeElement(node, candidatesOutArray, checkMode);
|
||||
@ -52934,6 +53002,10 @@ namespace JsxNames {
|
||||
export const LibraryManagedAttributes = "LibraryManagedAttributes" as __String;
|
||||
}
|
||||
|
||||
namespace ReactNames {
|
||||
export const Fragment = "Fragment" as __String;
|
||||
}
|
||||
|
||||
function getIterationTypesKeyFromIterationTypeKind(typeKind: IterationTypeKind) {
|
||||
switch (typeKind) {
|
||||
case IterationTypeKind.Yield:
|
||||
|
||||
@ -3976,6 +3976,10 @@
|
||||
"category": "Error",
|
||||
"code": 2878
|
||||
},
|
||||
"Using JSX fragments requires fragment factory '{0}' to be in scope, but it could not be found.": {
|
||||
"category": "Error",
|
||||
"code": 2879
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
@ -5530,7 +5534,6 @@
|
||||
"category": "Message",
|
||||
"code": 6243
|
||||
},
|
||||
|
||||
"Modules": {
|
||||
"category": "Message",
|
||||
"code": 6244
|
||||
|
||||
@ -3126,7 +3126,7 @@ export type CallLikeExpression =
|
||||
| NewExpression
|
||||
| TaggedTemplateExpression
|
||||
| Decorator
|
||||
| JsxOpeningLikeElement
|
||||
| JsxCallLike
|
||||
| InstanceofExpression;
|
||||
|
||||
export interface AsExpression extends Expression {
|
||||
@ -3187,6 +3187,10 @@ export type JsxOpeningLikeElement =
|
||||
| JsxSelfClosingElement
|
||||
| JsxOpeningElement;
|
||||
|
||||
export type JsxCallLike =
|
||||
| JsxOpeningLikeElement
|
||||
| JsxOpeningFragment;
|
||||
|
||||
export type JsxAttributeLike =
|
||||
| JsxAttribute
|
||||
| JsxSpreadAttribute;
|
||||
@ -6208,7 +6212,6 @@ export interface NodeLinks {
|
||||
resolvedType?: Type; // Cached type of type node
|
||||
resolvedSignature?: Signature; // Cached signature of signature node or call expression
|
||||
resolvedSymbol?: Symbol; // Cached name resolution result
|
||||
resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result
|
||||
effectsSignature?: Signature; // Signature with possible control flow effects
|
||||
enumMemberValue?: EvaluatorResult; // Constant value of enum member
|
||||
isVisible?: boolean; // Is this node visible
|
||||
@ -6216,11 +6219,11 @@ export interface NodeLinks {
|
||||
hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context
|
||||
jsxFlags: JsxFlags; // flags for knowing what kind of element/attributes we're dealing with
|
||||
resolvedJsxElementAttributesType?: Type; // resolved element attributes type of a JSX openinglike element
|
||||
resolvedJsxElementAllAttributesType?: Type; // resolved all element attributes type of a JSX openinglike element
|
||||
resolvedJSDocType?: Type; // Resolved type of a JSDoc type reference
|
||||
switchTypes?: Type[]; // Cached array of switch case expression types
|
||||
jsxNamespace?: Symbol | false; // Resolved jsx namespace symbol for this node
|
||||
jsxImplicitImportContainer?: Symbol | false; // Resolved module symbol the implicit jsx import of this file should refer to
|
||||
jsxFragmentType?: Type; // Type of the JSX fragment element, set per SourceFile if a jsxFragment is checked in the file
|
||||
contextFreeType?: Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive
|
||||
deferredNodes?: Set<Node>; // Set of nodes whose checking has been deferred
|
||||
capturedBlockScopeBindings?: Symbol[]; // Block-scoped bindings captured beneath this part of an IterationStatement
|
||||
|
||||
@ -3383,6 +3383,8 @@ export function getInvokedExpression(node: CallLikeExpression): Expression | Jsx
|
||||
return node.tagName;
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return node.right;
|
||||
case SyntaxKind.JsxOpeningFragment:
|
||||
return node;
|
||||
default:
|
||||
return node.expression;
|
||||
}
|
||||
|
||||
@ -204,6 +204,7 @@ import {
|
||||
JSDocTypedefTag,
|
||||
JSDocTypeTag,
|
||||
JsxAttributeLike,
|
||||
JsxCallLike,
|
||||
JsxChild,
|
||||
JsxExpression,
|
||||
JsxOpeningLikeElement,
|
||||
@ -1957,13 +1958,16 @@ export function isCallLikeOrFunctionLikeExpression(node: Node): node is CallLike
|
||||
|
||||
export function isCallLikeExpression(node: Node): node is CallLikeExpression {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
case SyntaxKind.Decorator:
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
case SyntaxKind.JsxOpeningFragment:
|
||||
return true;
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return (node as BinaryExpression).operatorToken.kind === SyntaxKind.InstanceOfKeyword;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -2479,6 +2483,13 @@ export function isJsxOpeningLikeElement(node: Node): node is JsxOpeningLikeEleme
|
||||
|| kind === SyntaxKind.JsxSelfClosingElement;
|
||||
}
|
||||
|
||||
export function isJsxCallLike(node: Node): node is JsxCallLike {
|
||||
const kind = node.kind;
|
||||
return kind === SyntaxKind.JsxOpeningElement
|
||||
|| kind === SyntaxKind.JsxSelfClosingElement
|
||||
|| kind === SyntaxKind.JsxOpeningFragment;
|
||||
}
|
||||
|
||||
// Clauses
|
||||
|
||||
export function isCaseOrDefaultClause(node: Node): node is CaseOrDefaultClause {
|
||||
|
||||
@ -5148,7 +5148,7 @@ declare namespace ts {
|
||||
interface InstanceofExpression extends BinaryExpression {
|
||||
readonly operatorToken: Token<SyntaxKind.InstanceOfKeyword>;
|
||||
}
|
||||
type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression | Decorator | JsxOpeningLikeElement | InstanceofExpression;
|
||||
type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression | Decorator | JsxCallLike | InstanceofExpression;
|
||||
interface AsExpression extends Expression {
|
||||
readonly kind: SyntaxKind.AsExpression;
|
||||
readonly expression: Expression;
|
||||
@ -5184,6 +5184,7 @@ declare namespace ts {
|
||||
readonly closingElement: JsxClosingElement;
|
||||
}
|
||||
type JsxOpeningLikeElement = JsxSelfClosingElement | JsxOpeningElement;
|
||||
type JsxCallLike = JsxOpeningLikeElement | JsxOpeningFragment;
|
||||
type JsxAttributeLike = JsxAttribute | JsxSpreadAttribute;
|
||||
type JsxAttributeName = Identifier | JsxNamespacedName;
|
||||
type JsxTagNameExpression = Identifier | ThisExpression | JsxTagNamePropertyAccess | JsxNamespacedName;
|
||||
@ -8800,6 +8801,7 @@ declare namespace ts {
|
||||
function isJsxAttributeLike(node: Node): node is JsxAttributeLike;
|
||||
function isStringLiteralOrJsxExpression(node: Node): node is StringLiteral | JsxExpression;
|
||||
function isJsxOpeningLikeElement(node: Node): node is JsxOpeningLikeElement;
|
||||
function isJsxCallLike(node: Node): node is JsxCallLike;
|
||||
function isCaseOrDefaultClause(node: Node): node is CaseOrDefaultClause;
|
||||
/** True if node is of a kind that may contain comment text. */
|
||||
function isJSDocCommentContainingNode(node: Node): boolean;
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
preacty-no-fragment.tsx(5,12): error TS6133: 'Fragment' is declared but its value is never read.
|
||||
preacty-only-fragment-no-jsx.tsx(6,1): error TS2874: This JSX tag requires 'h' to be in scope, but it could not be found.
|
||||
snabbdomy-only-fragment-no-jsx.tsx(4,1): error TS2874: This JSX tag requires 'jsx' to be in scope, but it could not be found.
|
||||
snabbdomy-only-fragment-no-jsx.tsx(4,1): error TS2879: Using JSX fragments requires fragment factory 'null' to be in scope, but it could not be found.
|
||||
snabbdomy-only-fragment.tsx(4,1): error TS2879: Using JSX fragments requires fragment factory 'null' to be in scope, but it could not be found.
|
||||
snabbdomy.tsx(4,1): error TS2879: Using JSX fragments requires fragment factory 'null' to be in scope, but it could not be found.
|
||||
|
||||
|
||||
==== renderer.d.ts (0 errors) ====
|
||||
@ -23,11 +26,13 @@ snabbdomy-only-fragment-no-jsx.tsx(4,1): error TS2874: This JSX tag requires 'js
|
||||
import {h, Fragment} from "./renderer";
|
||||
<><div></div></>
|
||||
|
||||
==== snabbdomy.tsx (0 errors) ====
|
||||
==== snabbdomy.tsx (1 errors) ====
|
||||
/* @jsx jsx */
|
||||
/* @jsxfrag null */
|
||||
import {jsx} from "./renderer";
|
||||
<><span></span></>
|
||||
~~
|
||||
!!! error TS2879: Using JSX fragments requires fragment factory 'null' to be in scope, but it could not be found.
|
||||
|
||||
==== preacty-only-fragment.tsx (0 errors) ====
|
||||
/**
|
||||
@ -37,11 +42,13 @@ snabbdomy-only-fragment-no-jsx.tsx(4,1): error TS2874: This JSX tag requires 'js
|
||||
import {h, Fragment} from "./renderer";
|
||||
<></>
|
||||
|
||||
==== snabbdomy-only-fragment.tsx (0 errors) ====
|
||||
==== snabbdomy-only-fragment.tsx (1 errors) ====
|
||||
/* @jsx jsx */
|
||||
/* @jsxfrag null */
|
||||
import {jsx} from "./renderer";
|
||||
<></>
|
||||
~~
|
||||
!!! error TS2879: Using JSX fragments requires fragment factory 'null' to be in scope, but it could not be found.
|
||||
|
||||
==== preacty-only-fragment-no-jsx.tsx (1 errors) ====
|
||||
/**
|
||||
@ -53,13 +60,15 @@ snabbdomy-only-fragment-no-jsx.tsx(4,1): error TS2874: This JSX tag requires 'js
|
||||
~~
|
||||
!!! error TS2874: This JSX tag requires 'h' to be in scope, but it could not be found.
|
||||
|
||||
==== snabbdomy-only-fragment-no-jsx.tsx (1 errors) ====
|
||||
==== snabbdomy-only-fragment-no-jsx.tsx (2 errors) ====
|
||||
/* @jsx jsx */
|
||||
/* @jsxfrag null */
|
||||
import {} from "./renderer";
|
||||
<></>
|
||||
~~
|
||||
!!! error TS2874: This JSX tag requires 'jsx' to be in scope, but it could not be found.
|
||||
~~
|
||||
!!! error TS2879: Using JSX fragments requires fragment factory 'null' to be in scope, but it could not be found.
|
||||
|
||||
==== preacty-no-fragment.tsx (1 errors) ====
|
||||
/**
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
snabbdomy.tsx(6,1): error TS2879: Using JSX fragments requires fragment factory 'null' to be in scope, but it could not be found.
|
||||
|
||||
|
||||
==== react.d.ts (0 errors) ====
|
||||
declare global {
|
||||
namespace JSX {
|
||||
interface IntrinsicElements {
|
||||
[e: string]: any;
|
||||
}
|
||||
}
|
||||
}
|
||||
export function createElement(): void;
|
||||
export function Fragment(): void;
|
||||
|
||||
==== preact.d.ts (0 errors) ====
|
||||
export function h(): void;
|
||||
export function Frag(): void;
|
||||
|
||||
==== snabbdom.d.ts (0 errors) ====
|
||||
export function h(): void;
|
||||
|
||||
==== reacty.tsx (0 errors) ====
|
||||
import {createElement, Fragment} from "./react";
|
||||
<><span></span></>
|
||||
|
||||
==== preacty.tsx (0 errors) ====
|
||||
/**
|
||||
* @jsx h
|
||||
* @jsxFrag Frag
|
||||
*/
|
||||
import {h, Frag} from "./preact";
|
||||
<><div></div></>
|
||||
|
||||
==== snabbdomy.tsx (1 errors) ====
|
||||
/**
|
||||
* @jsx h
|
||||
* @jsxfrag null
|
||||
*/
|
||||
import {h} from "./snabbdom";
|
||||
<><div></div></>
|
||||
~~
|
||||
!!! error TS2879: Using JSX fragments requires fragment factory 'null' to be in scope, but it could not be found.
|
||||
|
||||
==== mix-n-match.tsx (0 errors) ====
|
||||
/* @jsx h */
|
||||
/* @jsxFrag Fragment */
|
||||
import {h} from "./preact";
|
||||
import {Fragment} from "./react";
|
||||
<><span></span></>
|
||||
@ -43,8 +43,10 @@ import {createElement, Fragment} from "./react";
|
||||
> : ^^^^^^
|
||||
|
||||
<><span></span></>
|
||||
><><span></span></> : error
|
||||
><span></span> : error
|
||||
><><span></span></> : any
|
||||
> : ^^^
|
||||
><span></span> : any
|
||||
> : ^^^
|
||||
>span : any
|
||||
> : ^^^
|
||||
>span : any
|
||||
@ -62,8 +64,10 @@ import {h, Frag} from "./preact";
|
||||
> : ^^^^^^
|
||||
|
||||
<><div></div></>
|
||||
><><div></div></> : error
|
||||
><div></div> : error
|
||||
><><div></div></> : any
|
||||
> : ^^^
|
||||
><div></div> : any
|
||||
> : ^^^
|
||||
>div : any
|
||||
> : ^^^
|
||||
>div : any
|
||||
@ -79,8 +83,10 @@ import {h} from "./snabbdom";
|
||||
> : ^^^^^^
|
||||
|
||||
<><div></div></>
|
||||
><><div></div></> : error
|
||||
><div></div> : error
|
||||
><><div></div></> : any
|
||||
> : ^^^
|
||||
><div></div> : any
|
||||
> : ^^^
|
||||
>div : any
|
||||
> : ^^^
|
||||
>div : any
|
||||
@ -98,8 +104,10 @@ import {Fragment} from "./react";
|
||||
> : ^^^^^^
|
||||
|
||||
<><span></span></>
|
||||
><><span></span></> : error
|
||||
><span></span> : error
|
||||
><><span></span></> : any
|
||||
> : ^^^
|
||||
><span></span> : any
|
||||
> : ^^^
|
||||
>span : any
|
||||
> : ^^^
|
||||
>span : any
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
index.tsx(3,1): error TS2874: This JSX tag requires 'React' to be in scope, but it could not be found.
|
||||
index.tsx(3,1): error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
index.tsx(3,1): error TS17017: An @jsxFrag pragma is required when using an @jsx pragma with JSX fragments.
|
||||
reacty.tsx(3,1): error TS17017: An @jsxFrag pragma is required when using an @jsx pragma with JSX fragments.
|
||||
|
||||
@ -19,11 +20,13 @@ reacty.tsx(3,1): error TS17017: An @jsxFrag pragma is required when using an @js
|
||||
<><h></h></>
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS17017: An @jsxFrag pragma is required when using an @jsx pragma with JSX fragments.
|
||||
==== index.tsx (2 errors) ====
|
||||
==== index.tsx (3 errors) ====
|
||||
/** @jsx dom */
|
||||
import { dom } from "./renderer";
|
||||
<><h></h></>
|
||||
~~
|
||||
!!! error TS2874: This JSX tag requires 'React' to be in scope, but it could not be found.
|
||||
~~
|
||||
!!! error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS17017: An @jsxFrag pragma is required when using an @jsx pragma with JSX fragments.
|
||||
@ -0,0 +1,10 @@
|
||||
jsxFactoryAndJsxFragmentFactoryNull.tsx(3,1): error TS2879: Using JSX fragments requires fragment factory 'null' to be in scope, but it could not be found.
|
||||
|
||||
|
||||
==== jsxFactoryAndJsxFragmentFactoryNull.tsx (1 errors) ====
|
||||
declare var h: any;
|
||||
|
||||
<></>;
|
||||
~~
|
||||
!!! error TS2879: Using JSX fragments requires fragment factory 'null' to be in scope, but it could not be found.
|
||||
<><span>1</span><><span>2.1</span><span>2.2</span></></>;
|
||||
@ -3,24 +3,31 @@
|
||||
=== jsxFactoryAndJsxFragmentFactoryNull.tsx ===
|
||||
declare var h: any;
|
||||
>h : any
|
||||
> : ^^^
|
||||
|
||||
<></>;
|
||||
><></> : error
|
||||
><></> : any
|
||||
> : ^^^
|
||||
|
||||
<><span>1</span><><span>2.1</span><span>2.2</span></></>;
|
||||
><><span>1</span><><span>2.1</span><span>2.2</span></></> : error
|
||||
><span>1</span> : error
|
||||
><><span>1</span><><span>2.1</span><span>2.2</span></></> : any
|
||||
> : ^^^
|
||||
><span>1</span> : any
|
||||
> : ^^^
|
||||
>span : any
|
||||
> : ^^^
|
||||
>span : any
|
||||
> : ^^^
|
||||
><><span>2.1</span><span>2.2</span></> : error
|
||||
><span>2.1</span> : error
|
||||
><><span>2.1</span><span>2.2</span></> : any
|
||||
> : ^^^
|
||||
><span>2.1</span> : any
|
||||
> : ^^^
|
||||
>span : any
|
||||
> : ^^^
|
||||
>span : any
|
||||
> : ^^^
|
||||
><span>2.2</span> : error
|
||||
><span>2.2</span> : any
|
||||
> : ^^^
|
||||
>span : any
|
||||
> : ^^^
|
||||
>span : any
|
||||
|
||||
22
tests/baselines/reference/jsxFragmentWrongType.errors.txt
Normal file
22
tests/baselines/reference/jsxFragmentWrongType.errors.txt
Normal file
@ -0,0 +1,22 @@
|
||||
a.tsx(6,28): error TS2322: Type '{ children: () => string; }' is not assignable to type '{ children?: ReactNode; }'.
|
||||
Types of property 'children' are incompatible.
|
||||
Type '() => string' is not assignable to type 'ReactNode'.
|
||||
a.tsx(7,47): error TS2322: Type '() => string' is not assignable to type 'ReactNode'.
|
||||
|
||||
|
||||
==== a.tsx (2 errors) ====
|
||||
/// <reference path="/.lib/react18/react18.d.ts" />
|
||||
/// <reference path="/.lib/react18/global.d.ts" />
|
||||
|
||||
const test = () => "asd";
|
||||
|
||||
const jsxWithJsxFragment = <>{test}</>;
|
||||
~~
|
||||
!!! error TS2322: Type '{ children: () => string; }' is not assignable to type '{ children?: ReactNode; }'.
|
||||
!!! error TS2322: Types of property 'children' are incompatible.
|
||||
!!! error TS2322: Type '() => string' is not assignable to type 'ReactNode'.
|
||||
const jsxWithReactFragment = <React.Fragment>{test}</React.Fragment>;
|
||||
~~~~
|
||||
!!! error TS2322: Type '() => string' is not assignable to type 'ReactNode'.
|
||||
!!! related TS6212 a.tsx:7:47: Did you mean to call this expression?
|
||||
|
||||
19
tests/baselines/reference/jsxFragmentWrongType.js
Normal file
19
tests/baselines/reference/jsxFragmentWrongType.js
Normal file
@ -0,0 +1,19 @@
|
||||
//// [tests/cases/compiler/jsxFragmentWrongType.tsx] ////
|
||||
|
||||
//// [a.tsx]
|
||||
/// <reference path="/.lib/react18/react18.d.ts" />
|
||||
/// <reference path="/.lib/react18/global.d.ts" />
|
||||
|
||||
const test = () => "asd";
|
||||
|
||||
const jsxWithJsxFragment = <>{test}</>;
|
||||
const jsxWithReactFragment = <React.Fragment>{test}</React.Fragment>;
|
||||
|
||||
|
||||
//// [a.js]
|
||||
"use strict";
|
||||
/// <reference path="react18/react18.d.ts" />
|
||||
/// <reference path="react18/global.d.ts" />
|
||||
const test = () => "asd";
|
||||
const jsxWithJsxFragment = React.createElement(React.Fragment, null, test);
|
||||
const jsxWithReactFragment = React.createElement(React.Fragment, null, test);
|
||||
23
tests/baselines/reference/jsxFragmentWrongType.symbols
Normal file
23
tests/baselines/reference/jsxFragmentWrongType.symbols
Normal file
@ -0,0 +1,23 @@
|
||||
//// [tests/cases/compiler/jsxFragmentWrongType.tsx] ////
|
||||
|
||||
=== a.tsx ===
|
||||
/// <reference path="react18/react18.d.ts" />
|
||||
/// <reference path="react18/global.d.ts" />
|
||||
|
||||
const test = () => "asd";
|
||||
>test : Symbol(test, Decl(a.tsx, 3, 5))
|
||||
|
||||
const jsxWithJsxFragment = <>{test}</>;
|
||||
>jsxWithJsxFragment : Symbol(jsxWithJsxFragment, Decl(a.tsx, 5, 5))
|
||||
>test : Symbol(test, Decl(a.tsx, 3, 5))
|
||||
|
||||
const jsxWithReactFragment = <React.Fragment>{test}</React.Fragment>;
|
||||
>jsxWithReactFragment : Symbol(jsxWithReactFragment, Decl(a.tsx, 6, 5))
|
||||
>React.Fragment : Symbol(React.Fragment, Decl(react18.d.ts, 390, 9))
|
||||
>React : Symbol(React, Decl(react18.d.ts, 62, 15))
|
||||
>Fragment : Symbol(React.Fragment, Decl(react18.d.ts, 390, 9))
|
||||
>test : Symbol(test, Decl(a.tsx, 3, 5))
|
||||
>React.Fragment : Symbol(React.Fragment, Decl(react18.d.ts, 390, 9))
|
||||
>React : Symbol(React, Decl(react18.d.ts, 62, 15))
|
||||
>Fragment : Symbol(React.Fragment, Decl(react18.d.ts, 390, 9))
|
||||
|
||||
45
tests/baselines/reference/jsxFragmentWrongType.types
Normal file
45
tests/baselines/reference/jsxFragmentWrongType.types
Normal file
@ -0,0 +1,45 @@
|
||||
//// [tests/cases/compiler/jsxFragmentWrongType.tsx] ////
|
||||
|
||||
=== Performance Stats ===
|
||||
Type Count: 1,000
|
||||
|
||||
=== a.tsx ===
|
||||
/// <reference path="react18/react18.d.ts" />
|
||||
/// <reference path="react18/global.d.ts" />
|
||||
|
||||
const test = () => "asd";
|
||||
>test : () => string
|
||||
> : ^^^^^^^^^^^^
|
||||
>() => "asd" : () => string
|
||||
> : ^^^^^^^^^^^^
|
||||
>"asd" : "asd"
|
||||
> : ^^^^^
|
||||
|
||||
const jsxWithJsxFragment = <>{test}</>;
|
||||
>jsxWithJsxFragment : JSX.Element
|
||||
> : ^^^^^^^^^^^
|
||||
><>{test}</> : JSX.Element
|
||||
> : ^^^^^^^^^^^
|
||||
>test : () => string
|
||||
> : ^^^^^^^^^^^^
|
||||
|
||||
const jsxWithReactFragment = <React.Fragment>{test}</React.Fragment>;
|
||||
>jsxWithReactFragment : JSX.Element
|
||||
> : ^^^^^^^^^^^
|
||||
><React.Fragment>{test}</React.Fragment> : JSX.Element
|
||||
> : ^^^^^^^^^^^
|
||||
>React.Fragment : React.ExoticComponent<{ children?: React.ReactNode | undefined; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^
|
||||
>React : typeof React
|
||||
> : ^^^^^^^^^^^^
|
||||
>Fragment : React.ExoticComponent<{ children?: React.ReactNode | undefined; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^
|
||||
>test : () => string
|
||||
> : ^^^^^^^^^^^^
|
||||
>React.Fragment : React.ExoticComponent<{ children?: React.ReactNode | undefined; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^
|
||||
>React : typeof React
|
||||
> : ^^^^^^^^^^^^
|
||||
>Fragment : React.ExoticComponent<{ children?: React.ReactNode | undefined; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
jsxJsxsCjsTransformCustomImport.tsx(2,11): error TS2875: This JSX tag requires the module path 'preact/jsx-runtime' to exist, but none could be found. Make sure you have types for the appropriate package installed.
|
||||
jsxJsxsCjsTransformCustomImport.tsx(2,11): error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
|
||||
|
||||
==== jsxJsxsCjsTransformCustomImport.tsx (1 errors) ====
|
||||
==== jsxJsxsCjsTransformCustomImport.tsx (2 errors) ====
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
const a = <>
|
||||
~~
|
||||
!!! error TS2875: This JSX tag requires the module path 'preact/jsx-runtime' to exist, but none could be found. Make sure you have types for the appropriate package installed.
|
||||
~~
|
||||
!!! error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
<p></p>
|
||||
text
|
||||
<div className="foo"></div>
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
jsxJsxsCjsTransformCustomImport.tsx(2,11): error TS2875: This JSX tag requires the module path 'preact/jsx-dev-runtime' to exist, but none could be found. Make sure you have types for the appropriate package installed.
|
||||
jsxJsxsCjsTransformCustomImport.tsx(2,11): error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
|
||||
|
||||
==== jsxJsxsCjsTransformCustomImport.tsx (1 errors) ====
|
||||
==== jsxJsxsCjsTransformCustomImport.tsx (2 errors) ====
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
const a = <>
|
||||
~~
|
||||
!!! error TS2875: This JSX tag requires the module path 'preact/jsx-dev-runtime' to exist, but none could be found. Make sure you have types for the appropriate package installed.
|
||||
~~
|
||||
!!! error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
<p></p>
|
||||
text
|
||||
<div className="foo"></div>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
preact.tsx(3,11): error TS2875: This JSX tag requires the module path 'preact/jsx-runtime' to exist, but none could be found. Make sure you have types for the appropriate package installed.
|
||||
preact.tsx(3,11): error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
|
||||
|
||||
==== react.tsx (0 errors) ====
|
||||
@ -12,12 +13,14 @@ preact.tsx(3,11): error TS2875: This JSX tag requires the module path 'preact/js
|
||||
</>
|
||||
|
||||
export {};
|
||||
==== preact.tsx (1 errors) ====
|
||||
==== preact.tsx (2 errors) ====
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
/* @jsxImportSource preact */
|
||||
const a = <>
|
||||
~~
|
||||
!!! error TS2875: This JSX tag requires the module path 'preact/jsx-runtime' to exist, but none could be found. Make sure you have types for the appropriate package installed.
|
||||
~~
|
||||
!!! error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
<p></p>
|
||||
text
|
||||
<div className="foo"></div>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
preact.tsx(3,11): error TS2875: This JSX tag requires the module path 'preact/jsx-dev-runtime' to exist, but none could be found. Make sure you have types for the appropriate package installed.
|
||||
preact.tsx(3,11): error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
|
||||
|
||||
==== react.tsx (0 errors) ====
|
||||
@ -12,12 +13,14 @@ preact.tsx(3,11): error TS2875: This JSX tag requires the module path 'preact/js
|
||||
</>
|
||||
|
||||
export {};
|
||||
==== preact.tsx (1 errors) ====
|
||||
==== preact.tsx (2 errors) ====
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
/* @jsxImportSource preact */
|
||||
const a = <>
|
||||
~~
|
||||
!!! error TS2875: This JSX tag requires the module path 'preact/jsx-dev-runtime' to exist, but none could be found. Make sure you have types for the appropriate package installed.
|
||||
~~
|
||||
!!! error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
<p></p>
|
||||
text
|
||||
<div className="foo"></div>
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
index.js(2,12): error TS17014: JSX fragment has no corresponding closing tag.
|
||||
index.js(2,13): error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
index.js(2,13): error TS17004: Cannot use JSX unless the '--jsx' flag is provided.
|
||||
index.js(3,1): error TS1005: '</' expected.
|
||||
|
||||
|
||||
==== index.js (3 errors) ====
|
||||
==== index.js (4 errors) ====
|
||||
const x = "oops";
|
||||
const y = + <> x;
|
||||
~~~
|
||||
!!! error TS17014: JSX fragment has no corresponding closing tag.
|
||||
~~
|
||||
!!! error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
~~
|
||||
!!! error TS17004: Cannot use JSX unless the '--jsx' flag is provided.
|
||||
|
||||
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
index.tsx(3,14): error TS17008: JSX element 'number' has no corresponding closing tag.
|
||||
index.tsx(4,13): error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
index.tsx(4,13): error TS17014: JSX fragment has no corresponding closing tag.
|
||||
index.tsx(5,14): error TS1003: Identifier expected.
|
||||
index.tsx(5,18): error TS1382: Unexpected token. Did you mean `{'>'}` or `>`?
|
||||
index.tsx(6,1): error TS1005: '</' expected.
|
||||
|
||||
|
||||
==== index.tsx (5 errors) ====
|
||||
==== index.tsx (6 errors) ====
|
||||
const x = "oops";
|
||||
|
||||
const a = + <number> x;
|
||||
@ -13,6 +14,8 @@ index.tsx(6,1): error TS1005: '</' expected.
|
||||
!!! error TS17008: JSX element 'number' has no corresponding closing tag.
|
||||
const b = + <> x;
|
||||
~~
|
||||
!!! error TS2879: Using JSX fragments requires fragment factory 'React' to be in scope, but it could not be found.
|
||||
~~
|
||||
!!! error TS17014: JSX fragment has no corresponding closing tag.
|
||||
const c = + <1234> x;
|
||||
~~~~
|
||||
|
||||
15
tests/cases/compiler/jsxFragmentWrongType.tsx
Normal file
15
tests/cases/compiler/jsxFragmentWrongType.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
// @jsx: react
|
||||
// @strict: true
|
||||
// @skipLibCheck: true
|
||||
// @target: ES2017
|
||||
// @module: ESNext
|
||||
// @esModuleInterop: true
|
||||
|
||||
// @filename: a.tsx
|
||||
/// <reference path="/.lib/react18/react18.d.ts" />
|
||||
/// <reference path="/.lib/react18/global.d.ts" />
|
||||
|
||||
const test = () => "asd";
|
||||
|
||||
const jsxWithJsxFragment = <>{test}</>;
|
||||
const jsxWithReactFragment = <React.Fragment>{test}</React.Fragment>;
|
||||
Loading…
x
Reference in New Issue
Block a user