add jsx fragments to callLikeExpression (#59933)

This commit is contained in:
Isabel Duan 2024-09-27 15:16:29 -07:00 committed by GitHub
parent bd3d70058c
commit f6d2e73c5a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 487 additions and 166 deletions

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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 {

View File

@ -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;

View File

@ -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) ====
/**

View File

@ -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></>

View File

@ -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

View File

@ -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.

View File

@ -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></></>;

View File

@ -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

View 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?

View 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);

View 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))

View 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; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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.

View File

@ -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 `&gt;`?
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;
~~~~

View 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>;