diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f11112811f517..ff58a4e67ae8e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -361,7 +361,7 @@ namespace ts { // The presence of a particular fact means that the given test is true for some (and possibly all) values // of that kind of type. BaseStringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, - BaseStringFacts = BaseStringStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, + BaseStringFacts = BaseStringStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, StringStrictFacts = BaseStringStrictFacts | Truthy | Falsy, StringFacts = BaseStringFacts | Truthy, EmptyStringStrictFacts = BaseStringStrictFacts | Falsy, @@ -423,14 +423,20 @@ namespace ts { let _jsxNamespace: string; let _jsxFactoryEntity: EntityName; + let _jsxElementPropertiesName: string; + let _hasComputedJsxElementPropertiesName = false; + let _jsxElementChildrenPropertyName: string; + let _hasComputedJsxElementChildrenPropertyName = false; /** Things we lazy load from the JSX namespace */ const jsxTypes = createMap(); + const JsxNames = { JSX: "JSX", IntrinsicElements: "IntrinsicElements", ElementClass: "ElementClass", ElementAttributesPropertyNameContainer: "ElementAttributesProperty", + ElementChildrenAttributeNameContainer: "ElementChildrenAttribute", Element: "Element", IntrinsicAttributes: "IntrinsicAttributes", IntrinsicClassAttributes: "IntrinsicClassAttributes" @@ -468,7 +474,7 @@ namespace ts { return checker; function getJsxNamespace(): string { - if (_jsxNamespace === undefined) { + if (!_jsxNamespace) { _jsxNamespace = "React"; if (compilerOptions.jsxFactory) { _jsxFactoryEntity = parseIsolatedEntityName(compilerOptions.jsxFactory, languageVersion); @@ -1645,7 +1651,7 @@ namespace ts { } } - // May be an untyped module. If so, ignore resolutionDiagnostic. + // May be an untyped module. If so, ignore resolutionDiagnostic. if (!isRelative && resolvedModule && !extensionIsTypeScript(resolvedModule.extension)) { if (isForAugmentation) { const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented; @@ -4000,7 +4006,7 @@ namespace ts { type; } - function getTypeForDeclarationFromJSDocComment(declaration: Node ) { + function getTypeForDeclarationFromJSDocComment(declaration: Node) { const jsdocType = getJSDocType(declaration); if (jsdocType) { return getTypeFromTypeNode(jsdocType); @@ -5667,7 +5673,7 @@ namespace ts { function getConstraintOfType(type: TypeVariable | UnionOrIntersectionType): Type { return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type) : type.flags & TypeFlags.IndexedAccess ? getConstraintOfIndexedAccess(type) : - getBaseConstraintOfType(type); + getBaseConstraintOfType(type); } function getConstraintOfTypeParameter(typeParameter: TypeParameter): Type { @@ -5740,7 +5746,7 @@ namespace ts { } return t.flags & TypeFlags.Union && baseTypes.length === types.length ? getUnionType(baseTypes) : t.flags & TypeFlags.Intersection && baseTypes.length ? getIntersectionType(baseTypes) : - undefined; + undefined; } if (t.flags & TypeFlags.Index) { return stringType; @@ -5791,11 +5797,11 @@ namespace ts { const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type; return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t) : t.flags & TypeFlags.StringLike ? globalStringType : - t.flags & TypeFlags.NumberLike ? globalNumberType : - t.flags & TypeFlags.BooleanLike ? globalBooleanType : - t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType(/*reportErrors*/ languageVersion >= ScriptTarget.ES2015) : - t.flags & TypeFlags.NonPrimitive ? emptyObjectType : - t; + t.flags & TypeFlags.NumberLike ? globalNumberType : + t.flags & TypeFlags.BooleanLike ? globalBooleanType : + t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType(/*reportErrors*/ languageVersion >= ScriptTarget.ES2015) : + t.flags & TypeFlags.NonPrimitive ? emptyObjectType : + t; } function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol { @@ -7239,8 +7245,8 @@ namespace ts { function getIndexType(type: Type): Type { return maybeTypeOfKind(type, TypeFlags.TypeVariable) ? getIndexTypeForGenericType(type) : getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(type) : - type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringType : - getLiteralTypeFromPropertyNames(type); + type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringType : + getLiteralTypeFromPropertyNames(type); } function getIndexTypeOrString(type: Type): Type { @@ -7436,7 +7442,7 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type): Type { + function getSpreadType(left: Type, right: Type): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -7736,7 +7742,7 @@ namespace ts { function createTypeMapper(sources: Type[], targets: Type[]): TypeMapper { const mapper: TypeMapper = sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) : sources.length === 2 ? makeBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) : - makeArrayTypeMapper(sources, targets); + makeArrayTypeMapper(sources, targets); mapper.mappedTypes = sources; return mapper; } @@ -8543,7 +8549,7 @@ namespace ts { (globalNumberType === source && numberType === target) || (globalBooleanType === source && booleanType === target) || (getGlobalESSymbolType(/*reportErrors*/ false) === source && esSymbolType === target)) { - reportError(Diagnostics._0_is_a_primitive_but_1_is_a_wrapper_object_Prefer_using_0_when_possible, targetType, sourceType); + reportError(Diagnostics._0_is_a_primitive_but_1_is_a_wrapper_object_Prefer_using_0_when_possible, targetType, sourceType); } } @@ -8724,7 +8730,7 @@ namespace ts { // Use this property as the error node as this will be more helpful in // reasoning about what went wrong. Debug.assert(!!errorNode); - if (isJsxAttributes(errorNode)) { + if (isJsxAttributes(errorNode) || isJsxOpeningLikeElement(errorNode)) { // JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal. // However, using an object-literal error message will be very confusing to the users so we give different a message. reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(prop), typeToString(target)); @@ -9667,25 +9673,25 @@ namespace ts { function isLiteralType(type: Type): boolean { return type.flags & TypeFlags.Boolean ? true : type.flags & TypeFlags.Union ? type.flags & TypeFlags.Enum ? true : !forEach((type).types, t => !isUnitType(t)) : - isUnitType(type); + isUnitType(type); } function getBaseTypeOfLiteralType(type: Type): Type { return type.flags & TypeFlags.StringLiteral ? stringType : type.flags & TypeFlags.NumberLiteral ? numberType : - type.flags & TypeFlags.BooleanLiteral ? booleanType : - type.flags & TypeFlags.EnumLiteral ? (type).baseType : - type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(sameMap((type).types, getBaseTypeOfLiteralType)) : - type; + type.flags & TypeFlags.BooleanLiteral ? booleanType : + type.flags & TypeFlags.EnumLiteral ? (type).baseType : + type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(sameMap((type).types, getBaseTypeOfLiteralType)) : + type; } function getWidenedLiteralType(type: Type): Type { return type.flags & TypeFlags.StringLiteral && type.flags & TypeFlags.FreshLiteral ? stringType : type.flags & TypeFlags.NumberLiteral && type.flags & TypeFlags.FreshLiteral ? numberType : - type.flags & TypeFlags.BooleanLiteral ? booleanType : - type.flags & TypeFlags.EnumLiteral ? (type).baseType : - type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(sameMap((type).types, getWidenedLiteralType)) : - type; + type.flags & TypeFlags.BooleanLiteral ? booleanType : + type.flags & TypeFlags.EnumLiteral ? (type).baseType : + type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(sameMap((type).types, getWidenedLiteralType)) : + type; } /** @@ -9710,9 +9716,9 @@ namespace ts { function getFalsyFlags(type: Type): TypeFlags { return type.flags & TypeFlags.Union ? getFalsyFlagsOfTypes((type).types) : type.flags & TypeFlags.StringLiteral ? (type).text === "" ? TypeFlags.StringLiteral : 0 : - type.flags & TypeFlags.NumberLiteral ? (type).text === "0" ? TypeFlags.NumberLiteral : 0 : - type.flags & TypeFlags.BooleanLiteral ? type === falseType ? TypeFlags.BooleanLiteral : 0 : - type.flags & TypeFlags.PossiblyFalsy; + type.flags & TypeFlags.NumberLiteral ? (type).text === "0" ? TypeFlags.NumberLiteral : 0 : + type.flags & TypeFlags.BooleanLiteral ? type === falseType ? TypeFlags.BooleanLiteral : 0 : + type.flags & TypeFlags.PossiblyFalsy; } function includeFalsyTypes(type: Type, flags: TypeFlags) { @@ -10898,8 +10904,8 @@ namespace ts { isTypeSubsetOf(numberType, typeWithPrimitives) && maybeTypeOfKind(typeWithLiterals, TypeFlags.NumberLiteral)) { return mapType(typeWithPrimitives, t => t.flags & TypeFlags.String ? extractTypesOfKind(typeWithLiterals, TypeFlags.String | TypeFlags.StringLiteral) : - t.flags & TypeFlags.Number ? extractTypesOfKind(typeWithLiterals, TypeFlags.Number | TypeFlags.NumberLiteral) : - t); + t.flags & TypeFlags.Number ? extractTypesOfKind(typeWithLiterals, TypeFlags.Number | TypeFlags.NumberLiteral) : + t); } return typeWithPrimitives; } @@ -11475,7 +11481,7 @@ namespace ts { const discriminantType = getUnionType(clauseTypes); const caseType = discriminantType.flags & TypeFlags.Never ? neverType : - replacePrimitivesWithLiterals(filterType(type, t => isTypeComparableTo(discriminantType, t)), discriminantType); + replacePrimitivesWithLiterals(filterType(type, t => isTypeComparableTo(discriminantType, t)), discriminantType); if (!hasDefaultClause) { return caseType; } @@ -11555,8 +11561,8 @@ namespace ts { // two types. return isTypeSubtypeOf(candidate, type) ? candidate : isTypeAssignableTo(type, candidate) ? type : - isTypeAssignableTo(candidate, type) ? candidate : - getIntersectionType([type, candidate]); + isTypeAssignableTo(candidate, type) ? candidate : + getIntersectionType([type, candidate]); } function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { @@ -11833,7 +11839,7 @@ namespace ts { isInAmbientContext(declaration); const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, getRootDeclaration(declaration) as VariableLikeDeclaration) : type) : type === autoType || type === autoArrayType ? undefinedType : - includeFalsyTypes(type, TypeFlags.Undefined); + includeFalsyTypes(type, TypeFlags.Undefined); const flowType = getFlowTypeOfReference(node, type, initialType, flowContainer, !assumeInitialized); // A variable is considered uninitialized when it is possible to analyze the entire control flow graph // from declaration to use, and when the variable's declared type doesn't include undefined but the @@ -12340,7 +12346,7 @@ namespace ts { func.kind === SyntaxKind.GetAccessor || func.kind === SyntaxKind.SetAccessor) && func.parent.kind === SyntaxKind.ObjectLiteralExpression ? func.parent : func.kind === SyntaxKind.FunctionExpression && func.parent.kind === SyntaxKind.PropertyAssignment ? func.parent.parent : - undefined; + undefined; } function getThisTypeArgument(type: Type): Type { @@ -12671,6 +12677,36 @@ namespace ts { return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined; } + function getContextualTypeForJsxExpression(node: JsxExpression): Type { + // JSX expression can appear in two position : JSX Element's children or JSX attribute + const jsxAttributes = isJsxAttributeLike(node.parent) ? + node.parent.parent : + node.parent.openingElement.attributes; // node.parent is JsxElement + + // When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type + // which is a type of the parameter of the signature we are trying out. + // If there is no contextual type (e.g. we are trying to resolve stateful component), get attributes type from resolving element's tagName + const attributesType = getContextualType(jsxAttributes); + + if (!attributesType || isTypeAny(attributesType)) { + return undefined; + } + + if (isJsxAttribute(node.parent)) { + // JSX expression is in JSX attribute + return getTypeOfPropertyOfType(attributesType, (node.parent as JsxAttribute).name.text); + } + else if (node.parent.kind === SyntaxKind.JsxElement) { + // JSX expression is in children of JSX Element, we will look for an "children" atttribute (we get the name from JSX.ElementAttributesProperty) + const jsxChildrenPropertyName = getJsxElementChildrenPropertyname(); + return jsxChildrenPropertyName && jsxChildrenPropertyName !== "" ? getTypeOfPropertyOfType(attributesType, jsxChildrenPropertyName) : anyType; + } + else { + // JSX expression is in JSX spread attribute + return attributesType; + } + } + function getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute) { // When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type // which is a type of the parameter of the signature we are trying out. @@ -12754,7 +12790,7 @@ namespace ts { case SyntaxKind.ParenthesizedExpression: return getContextualType(parent); case SyntaxKind.JsxExpression: - return getContextualType(parent); + return getContextualTypeForJsxExpression(parent); case SyntaxKind.JsxAttribute: case SyntaxKind.JsxSpreadAttribute: return getContextualTypeForJsxAttribute(parent); @@ -13214,21 +13250,6 @@ namespace ts { checkExpression(node.closingElement.tagName); } - // Check children - for (const child of node.children) { - switch (child.kind) { - case SyntaxKind.JsxExpression: - checkJsxExpression(child); - break; - case SyntaxKind.JsxElement: - checkJsxElement(child); - break; - case SyntaxKind.JsxSelfClosingElement: - checkJsxSelfClosingElement(child); - break; - } - } - return getJsxGlobalElementType() || anyType; } @@ -13321,6 +13342,42 @@ namespace ts { } }); } + + // Handle children attribute + const parent = openingLikeElement.parent.kind === SyntaxKind.JsxElement ? openingLikeElement.parent as JsxElement : undefined; + // 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 && parent.children.length > 0) { + const childrenTypes: Type[] = []; + for (const child of (parent as JsxElement).children) { + // In React, JSX text that contains only whitespaces will be ignored so we don't want to type-check that + // because then type of children property will have constituent of string type. + if (child.kind === SyntaxKind.JsxText) { + if (!child.containsOnlyWhiteSpaces) { + childrenTypes.push(stringType); + } + } + else { + childrenTypes.push(checkExpression(child, checkMode)); + } + } + + // Error if there is a attribute named "children" and children element. + // This is because children element will overwrite the value from attributes + const jsxChildrenPropertyName = getJsxElementChildrenPropertyname(); + if (jsxChildrenPropertyName && jsxChildrenPropertyName !== "") { + if (attributesTable.has(jsxChildrenPropertyName)) { + error(attributes, Diagnostics._0_are_specified_twice_The_attribute_named_0_will_be_overwritten, jsxChildrenPropertyName); + } + + // If there are children in the body of JSX element, create dummy attribute "children" with anyType so that it will pass the attribute checking process + const childrenPropSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, jsxChildrenPropertyName); + childrenPropSymbol.type = childrenTypes.length === 1 ? + childrenTypes[0] : + createArrayType(getUnionType(childrenTypes, /*subtypeReduction*/ false)); + attributesTable.set(jsxChildrenPropertyName, childrenPropSymbol); + } + } + return createJsxAttributesType(attributes.symbol, attributesTable); /** @@ -13420,41 +13477,61 @@ namespace ts { return getUnionType(map(signatures, getReturnTypeOfSignature), /*subtypeReduction*/ true); } - /// e.g. "props" for React.d.ts, - /// or 'undefined' if ElementAttributesProperty doesn't exist (which means all - /// non-intrinsic elements' attributes type is 'any'), - /// or '' if it has 0 properties (which means every - /// non-intrinsic elements' attributes type is the element instance type) - function getJsxElementPropertiesName() { + /** + * Look into JSX namespace and then look for container with matching name as nameOfAttribPropContainer. + * Get a single property from that container if existed. Report an error if there are more than one property. + * + * @param nameOfAttribPropContainer a string of value JsxNames.ElementAttributesPropertyNameContainer or JsxNames.ElementChildrenAttributeNameContainer + * if other string is given or the container doesn't exist, return undefined. + */ + function getNameFromJsxElementAttributesContainer(nameOfAttribPropContainer: string): string { // JSX const jsxNamespace = getGlobalSymbol(JsxNames.JSX, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined); - // JSX.ElementAttributesProperty [symbol] - const attribsPropTypeSym = jsxNamespace && getSymbol(jsxNamespace.exports, JsxNames.ElementAttributesPropertyNameContainer, SymbolFlags.Type); - // JSX.ElementAttributesProperty [type] - const attribPropType = attribsPropTypeSym && getDeclaredTypeOfSymbol(attribsPropTypeSym); - // The properties of JSX.ElementAttributesProperty - const attribProperties = attribPropType && getPropertiesOfType(attribPropType); - - if (attribProperties) { + // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [symbol] + const jsxElementAttribPropInterfaceSym = jsxNamespace && getSymbol(jsxNamespace.exports, nameOfAttribPropContainer, SymbolFlags.Type); + // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [type] + const jsxElementAttribPropInterfaceType = jsxElementAttribPropInterfaceSym && getDeclaredTypeOfSymbol(jsxElementAttribPropInterfaceSym); + // The properties of JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute + const propertiesOfJsxElementAttribPropInterface = jsxElementAttribPropInterfaceType && getPropertiesOfType(jsxElementAttribPropInterfaceType); + if (propertiesOfJsxElementAttribPropInterface) { // Element Attributes has zero properties, so the element attributes type will be the class instance type - if (attribProperties.length === 0) { + if (propertiesOfJsxElementAttribPropInterface.length === 0) { return ""; } // Element Attributes has one property, so the element attributes type will be the type of the corresponding // property of the class instance type - else if (attribProperties.length === 1) { - return attribProperties[0].name; + else if (propertiesOfJsxElementAttribPropInterface.length === 1) { + return propertiesOfJsxElementAttribPropInterface[0].name; } - // More than one property on ElementAttributesProperty is an error - else { - error(attribsPropTypeSym.declarations[0], Diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, JsxNames.ElementAttributesPropertyNameContainer); - return undefined; + else if (propertiesOfJsxElementAttribPropInterface.length > 1) { + // More than one property on ElementAttributesProperty is an error + error(jsxElementAttribPropInterfaceSym.declarations[0], Diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, nameOfAttribPropContainer); } } - else { - // No interface exists, so the element attributes type will be an implicit any - return undefined; + return undefined; + } + + /// e.g. "props" for React.d.ts, + /// or 'undefined' if ElementAttributesProperty doesn't exist (which means all + /// non-intrinsic elements' attributes type is 'any'), + /// or '' if it has 0 properties (which means every + /// non-intrinsic elements' attributes type is the element instance type) + function getJsxElementPropertiesName() { + if (!_hasComputedJsxElementPropertiesName) { + _hasComputedJsxElementPropertiesName = true; + _jsxElementPropertiesName = getNameFromJsxElementAttributesContainer(JsxNames.ElementAttributesPropertyNameContainer); + } + + return _jsxElementPropertiesName; + } + + function getJsxElementChildrenPropertyname(): string { + if (!_hasComputedJsxElementChildrenPropertyName) { + _hasComputedJsxElementChildrenPropertyName = true; + _jsxElementChildrenPropertyName = getNameFromJsxElementAttributesContainer(JsxNames.ElementChildrenAttributeNameContainer); } + + return _jsxElementChildrenPropertyName; } /** diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index eb3e476a6f2b9..9ff983a3a8882 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2107,6 +2107,10 @@ "category": "Error", "code": 2709 }, + "'{0}' are specified twice. The attribute named '{0}' will be overwritten.": { + "category": "Error", + "code": 2710 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 69b5188878f86..669c9f5dd36ee 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2457,7 +2457,7 @@ namespace ts { let indentation: number; for (const line of lines) { for (let i = 0; i < line.length && (indentation === undefined || i < indentation); i++) { - if (!isWhiteSpace(line.charCodeAt(i))) { + if (!isWhiteSpaceLike(line.charCodeAt(i))) { if (indentation === undefined || i < indentation) { indentation = i; break; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 08144e7929952..8c11ae791c176 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3827,6 +3827,7 @@ namespace ts { function parseJsxText(): JsxText { const node = createNode(SyntaxKind.JsxText, scanner.getStartPos()); + node.containsOnlyWhiteSpaces = currentToken === SyntaxKind.JsxTextAllWhiteSpaces; currentToken = scanner.scanJsxToken(); return finishNode(node); } @@ -3834,6 +3835,7 @@ namespace ts { function parseJsxChild(): JsxChild { switch (token()) { case SyntaxKind.JsxText: + case SyntaxKind.JsxTextAllWhiteSpaces: return parseJsxText(); case SyntaxKind.OpenBraceToken: return parseJsxExpression(/*inExpressionContext*/ false); @@ -3863,7 +3865,10 @@ namespace ts { else if (token() === SyntaxKind.ConflictMarkerTrivia) { break; } - result.push(parseJsxChild()); + const child = parseJsxChild(); + if (child) { + result.push(child); + } } result.end = scanner.getTokenPos(); diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 41c48700a9a04..0ae0f07717904 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -366,7 +366,7 @@ namespace ts { return computeLineAndCharacterOfPosition(getLineStarts(sourceFile), position); } - export function isWhiteSpace(ch: number): boolean { + export function isWhiteSpaceLike(ch: number): boolean { return isWhiteSpaceSingleLine(ch) || isLineBreak(ch); } @@ -510,7 +510,7 @@ namespace ts { break; default: - if (ch > CharacterCodes.maxAsciiCharacter && (isWhiteSpace(ch))) { + if (ch > CharacterCodes.maxAsciiCharacter && (isWhiteSpaceLike(ch))) { pos++; continue; } @@ -691,7 +691,7 @@ namespace ts { } break scan; default: - if (ch > CharacterCodes.maxAsciiCharacter && (isWhiteSpace(ch))) { + if (ch > CharacterCodes.maxAsciiCharacter && (isWhiteSpaceLike(ch))) { if (hasPendingCommentRange && isLineBreak(ch)) { pendingHasTrailingNewLine = true; } @@ -1723,8 +1723,12 @@ namespace ts { return token = SyntaxKind.OpenBraceToken; } + // First non-whitespace character on this line. + let firstNonWhitespace = 0; + // These initial values are special because the first line is: + // firstNonWhitespace = 0 to indicate that we want leading whitspace, + while (pos < end) { - pos++; char = text.charCodeAt(pos); if (char === CharacterCodes.openBrace) { break; @@ -1736,8 +1740,23 @@ namespace ts { } break; } + + // FirstNonWhitespace is 0, then we only see whitespaces so far. If we see a linebreak, we want to ignore that whitespaces. + // i.e (- : whitespace) + //
---- + //
becomes
+ // + //
----
becomes
----
+ if (isLineBreak(char) && firstNonWhitespace === 0) { + firstNonWhitespace = -1; + } + else if (!isWhiteSpaceLike(char)) { + firstNonWhitespace = pos; + } + pos++; } - return token = SyntaxKind.JsxText; + + return firstNonWhitespace === -1 ? SyntaxKind.JsxTextAllWhiteSpaces : SyntaxKind.JsxText; } // Scans a JSX identifier; these differ from normal identifiers in that diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8874fd1a798ec..754350c37b2a1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -10,7 +10,7 @@ namespace ts { /** ES6 Map interface. */ export interface Map { - get(key: string): T; + get(key: string): T | undefined; has(key: string): boolean; set(key: string, value: T): this; delete(key: string): boolean; @@ -65,6 +65,7 @@ namespace ts { NumericLiteral, StringLiteral, JsxText, + JsxTextAllWhiteSpaces, RegularExpressionLiteral, NoSubstitutionTemplateLiteral, // Pseudo-literals @@ -1572,6 +1573,7 @@ namespace ts { export interface JsxText extends Node { kind: SyntaxKind.JsxText; + containsOnlyWhiteSpaces: boolean; parent?: JsxElement; } diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index b5c901482a7bc..01feaf390818e 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -54,7 +54,7 @@ namespace ts.formatting { let current = position; while (current > 0) { const char = sourceFile.text.charCodeAt(current); - if (!isWhiteSpace(char)) { + if (!isWhiteSpaceLike(char)) { break; } current--; diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index d7056cfdca241..e63c46ea8cedd 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -608,7 +608,7 @@ namespace ts.textChanges { if (force || !isTrivia(s)) { this.lastNonTriviaPosition = this.writer.getTextPos(); let i = 0; - while (isWhiteSpace(s.charCodeAt(s.length - i - 1))) { + while (isWhiteSpaceLike(s.charCodeAt(s.length - i - 1))) { i++; } // trim trailing whitespaces diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 815faac7417ec..1b0881a33ac10 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1380,7 +1380,7 @@ namespace ts { } export function getFirstNonSpaceCharacterPosition(text: string, position: number) { - while (isWhiteSpace(text.charCodeAt(position))) { + while (isWhiteSpaceLike(text.charCodeAt(position))) { position += 1; } return position; diff --git a/tests/baselines/reference/checkJsxChildrenProperty1.js b/tests/baselines/reference/checkJsxChildrenProperty1.js new file mode 100644 index 0000000000000..44c1ca8a72945 --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty1.js @@ -0,0 +1,39 @@ +//// [file.tsx] +import React = require('react'); + +interface Prop { + a: number, + b: string, + children: string | JSX.Element +} + +function Comp(p: Prop) { + return
{p.b}
; +} + +// OK +let k = ; +let k1 = + + hi hi hi! + ; +let k2 = + +
hi hi hi!
+
; + +//// [file.jsx] +"use strict"; +exports.__esModule = true; +var React = require("react"); +function Comp(p) { + return
{p.b}
; +} +// OK +var k = ; +var k1 = + hi hi hi! + ; +var k2 = +
hi hi hi!
+
; diff --git a/tests/baselines/reference/checkJsxChildrenProperty1.symbols b/tests/baselines/reference/checkJsxChildrenProperty1.symbols new file mode 100644 index 0000000000000..8793d0edd496d --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty1.symbols @@ -0,0 +1,67 @@ +=== tests/cases/conformance/jsx/file.tsx === +import React = require('react'); +>React : Symbol(React, Decl(file.tsx, 0, 0)) + +interface Prop { +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) + + a: number, +>a : Symbol(Prop.a, Decl(file.tsx, 2, 16)) + + b: string, +>b : Symbol(Prop.b, Decl(file.tsx, 3, 14)) + + children: string | JSX.Element +>children : Symbol(Prop.children, Decl(file.tsx, 4, 14)) +>JSX : Symbol(JSX, Decl(react.d.ts, 2352, 1)) +>Element : Symbol(JSX.Element, Decl(react.d.ts, 2355, 27)) +} + +function Comp(p: Prop) { +>Comp : Symbol(Comp, Decl(file.tsx, 6, 1)) +>p : Symbol(p, Decl(file.tsx, 8, 14)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) + + return
{p.b}
; +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>p.b : Symbol(Prop.b, Decl(file.tsx, 3, 14)) +>p : Symbol(p, Decl(file.tsx, 8, 14)) +>b : Symbol(Prop.b, Decl(file.tsx, 3, 14)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +} + +// OK +let k = ; +>k : Symbol(k, Decl(file.tsx, 13, 3)) +>Comp : Symbol(Comp, Decl(file.tsx, 6, 1)) +>a : Symbol(a, Decl(file.tsx, 13, 13)) +>b : Symbol(b, Decl(file.tsx, 13, 20)) +>children : Symbol(children, Decl(file.tsx, 13, 27)) + +let k1 = +>k1 : Symbol(k1, Decl(file.tsx, 14, 3)) + + +>Comp : Symbol(Comp, Decl(file.tsx, 6, 1)) +>a : Symbol(a, Decl(file.tsx, 15, 9)) +>b : Symbol(b, Decl(file.tsx, 15, 16)) + + hi hi hi! + ; +>Comp : Symbol(Comp, Decl(file.tsx, 6, 1)) + +let k2 = +>k2 : Symbol(k2, Decl(file.tsx, 18, 3)) + + +>Comp : Symbol(Comp, Decl(file.tsx, 6, 1)) +>a : Symbol(a, Decl(file.tsx, 19, 9)) +>b : Symbol(b, Decl(file.tsx, 19, 16)) + +
hi hi hi!
+>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) + +
; +>Comp : Symbol(Comp, Decl(file.tsx, 6, 1)) + diff --git a/tests/baselines/reference/checkJsxChildrenProperty1.types b/tests/baselines/reference/checkJsxChildrenProperty1.types new file mode 100644 index 0000000000000..821f95d9ae71b --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty1.types @@ -0,0 +1,75 @@ +=== tests/cases/conformance/jsx/file.tsx === +import React = require('react'); +>React : typeof React + +interface Prop { +>Prop : Prop + + a: number, +>a : number + + b: string, +>b : string + + children: string | JSX.Element +>children : string | JSX.Element +>JSX : any +>Element : JSX.Element +} + +function Comp(p: Prop) { +>Comp : (p: Prop) => JSX.Element +>p : Prop +>Prop : Prop + + return
{p.b}
; +>
{p.b}
: JSX.Element +>div : any +>p.b : string +>p : Prop +>b : string +>div : any +} + +// OK +let k = ; +>k : JSX.Element +> : JSX.Element +>Comp : (p: Prop) => JSX.Element +>a : number +>10 : 10 +>b : string +>children : string + +let k1 = +>k1 : JSX.Element + + +> hi hi hi! : JSX.Element +>Comp : (p: Prop) => JSX.Element +>a : number +>10 : 10 +>b : string + + hi hi hi! + ; +>Comp : (p: Prop) => JSX.Element + +let k2 = +>k2 : JSX.Element + + +>
hi hi hi!
: JSX.Element +>Comp : (p: Prop) => JSX.Element +>a : number +>10 : 10 +>b : string + +
hi hi hi!
+>
hi hi hi!
: JSX.Element +>div : any +>div : any + +
; +>Comp : (p: Prop) => JSX.Element + diff --git a/tests/baselines/reference/checkJsxChildrenProperty10.js b/tests/baselines/reference/checkJsxChildrenProperty10.js new file mode 100644 index 0000000000000..f022b28f20c28 --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty10.js @@ -0,0 +1,38 @@ +//// [file.tsx] +declare module JSX { + interface Element { } + interface ElementAttributesProperty { props: {} } + interface IntrinsicElements { + div: any; + h2: any; + h1: any; + } +} + +class Button { + props: {} + render() { + return (
My Button
) + } +} + +// OK +let k1 =

Hello

world

; +let k2 =

Hello

{(user: any) =>

{user.name}

}
; +let k3 =
{1} {"That is a number"}
; +let k4 = ; + +//// [file.jsx] +var Button = (function () { + function Button() { + } + Button.prototype.render = function () { + return (
My Button
); + }; + return Button; +}()); +// OK +var k1 =

Hello

world

; +var k2 =

Hello

{function (user) { return

{user.name}

; }}
; +var k3 =
{1} {"That is a number"}
; +var k4 = ; diff --git a/tests/baselines/reference/checkJsxChildrenProperty10.symbols b/tests/baselines/reference/checkJsxChildrenProperty10.symbols new file mode 100644 index 0000000000000..bf054377fb16a --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty10.symbols @@ -0,0 +1,73 @@ +=== tests/cases/conformance/jsx/file.tsx === +declare module JSX { +>JSX : Symbol(JSX, Decl(file.tsx, 0, 0)) + + interface Element { } +>Element : Symbol(Element, Decl(file.tsx, 0, 20)) + + interface ElementAttributesProperty { props: {} } +>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(file.tsx, 1, 22)) +>props : Symbol(ElementAttributesProperty.props, Decl(file.tsx, 2, 38)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 2, 50)) + + div: any; +>div : Symbol(IntrinsicElements.div, Decl(file.tsx, 3, 30)) + + h2: any; +>h2 : Symbol(IntrinsicElements.h2, Decl(file.tsx, 4, 11)) + + h1: any; +>h1 : Symbol(IntrinsicElements.h1, Decl(file.tsx, 5, 10)) + } +} + +class Button { +>Button : Symbol(Button, Decl(file.tsx, 8, 1)) + + props: {} +>props : Symbol(Button.props, Decl(file.tsx, 10, 14)) + + render() { +>render : Symbol(Button.render, Decl(file.tsx, 11, 10)) + + return (
My Button
) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) + } +} + +// OK +let k1 =

Hello

world

; +>k1 : Symbol(k1, Decl(file.tsx, 18, 3)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(file.tsx, 5, 10)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(file.tsx, 5, 10)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) + +let k2 =

Hello

{(user: any) =>

{user.name}

}
; +>k2 : Symbol(k2, Decl(file.tsx, 19, 3)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>user : Symbol(user, Decl(file.tsx, 19, 34)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>user : Symbol(user, Decl(file.tsx, 19, 34)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) + +let k3 =
{1} {"That is a number"}
; +>k3 : Symbol(k3, Decl(file.tsx, 20, 3)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) + +let k4 = ; +>k4 : Symbol(k4, Decl(file.tsx, 21, 3)) +>Button : Symbol(Button, Decl(file.tsx, 8, 1)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>Button : Symbol(Button, Decl(file.tsx, 8, 1)) + diff --git a/tests/baselines/reference/checkJsxChildrenProperty10.types b/tests/baselines/reference/checkJsxChildrenProperty10.types new file mode 100644 index 0000000000000..cee5995b8515e --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty10.types @@ -0,0 +1,89 @@ +=== tests/cases/conformance/jsx/file.tsx === +declare module JSX { +>JSX : any + + interface Element { } +>Element : Element + + interface ElementAttributesProperty { props: {} } +>ElementAttributesProperty : ElementAttributesProperty +>props : {} + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + div: any; +>div : any + + h2: any; +>h2 : any + + h1: any; +>h1 : any + } +} + +class Button { +>Button : Button + + props: {} +>props : {} + + render() { +>render : () => JSX.Element + + return (
My Button
) +>(
My Button
) : JSX.Element +>
My Button
: JSX.Element +>div : any +>div : any + } +} + +// OK +let k1 =

Hello

world

; +>k1 : JSX.Element +>

Hello

world

: JSX.Element +>div : any +>

Hello

: JSX.Element +>h2 : any +>h2 : any +>

world

: JSX.Element +>h1 : any +>h1 : any +>div : any + +let k2 =

Hello

{(user: any) =>

{user.name}

}
; +>k2 : JSX.Element +>

Hello

{(user: any) =>

{user.name}

}
: JSX.Element +>div : any +>

Hello

: JSX.Element +>h2 : any +>h2 : any +>(user: any) =>

{user.name}

: (user: any) => JSX.Element +>user : any +>

{user.name}

: JSX.Element +>h2 : any +>user.name : any +>user : any +>name : any +>h2 : any +>div : any + +let k3 =
{1} {"That is a number"}
; +>k3 : JSX.Element +>
{1} {"That is a number"}
: JSX.Element +>div : any +>1 : 1 +>"That is a number" : "That is a number" +>div : any + +let k4 = ; +>k4 : JSX.Element +> : JSX.Element +>Button : typeof Button +>

Hello

: JSX.Element +>h2 : any +>h2 : any +>Button : typeof Button + diff --git a/tests/baselines/reference/checkJsxChildrenProperty11.js b/tests/baselines/reference/checkJsxChildrenProperty11.js new file mode 100644 index 0000000000000..f022b28f20c28 --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty11.js @@ -0,0 +1,38 @@ +//// [file.tsx] +declare module JSX { + interface Element { } + interface ElementAttributesProperty { props: {} } + interface IntrinsicElements { + div: any; + h2: any; + h1: any; + } +} + +class Button { + props: {} + render() { + return (
My Button
) + } +} + +// OK +let k1 =

Hello

world

; +let k2 =

Hello

{(user: any) =>

{user.name}

}
; +let k3 =
{1} {"That is a number"}
; +let k4 = ; + +//// [file.jsx] +var Button = (function () { + function Button() { + } + Button.prototype.render = function () { + return (
My Button
); + }; + return Button; +}()); +// OK +var k1 =

Hello

world

; +var k2 =

Hello

{function (user) { return

{user.name}

; }}
; +var k3 =
{1} {"That is a number"}
; +var k4 = ; diff --git a/tests/baselines/reference/checkJsxChildrenProperty11.symbols b/tests/baselines/reference/checkJsxChildrenProperty11.symbols new file mode 100644 index 0000000000000..bf054377fb16a --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty11.symbols @@ -0,0 +1,73 @@ +=== tests/cases/conformance/jsx/file.tsx === +declare module JSX { +>JSX : Symbol(JSX, Decl(file.tsx, 0, 0)) + + interface Element { } +>Element : Symbol(Element, Decl(file.tsx, 0, 20)) + + interface ElementAttributesProperty { props: {} } +>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(file.tsx, 1, 22)) +>props : Symbol(ElementAttributesProperty.props, Decl(file.tsx, 2, 38)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 2, 50)) + + div: any; +>div : Symbol(IntrinsicElements.div, Decl(file.tsx, 3, 30)) + + h2: any; +>h2 : Symbol(IntrinsicElements.h2, Decl(file.tsx, 4, 11)) + + h1: any; +>h1 : Symbol(IntrinsicElements.h1, Decl(file.tsx, 5, 10)) + } +} + +class Button { +>Button : Symbol(Button, Decl(file.tsx, 8, 1)) + + props: {} +>props : Symbol(Button.props, Decl(file.tsx, 10, 14)) + + render() { +>render : Symbol(Button.render, Decl(file.tsx, 11, 10)) + + return (
My Button
) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) + } +} + +// OK +let k1 =

Hello

world

; +>k1 : Symbol(k1, Decl(file.tsx, 18, 3)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(file.tsx, 5, 10)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(file.tsx, 5, 10)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) + +let k2 =

Hello

{(user: any) =>

{user.name}

}
; +>k2 : Symbol(k2, Decl(file.tsx, 19, 3)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>user : Symbol(user, Decl(file.tsx, 19, 34)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>user : Symbol(user, Decl(file.tsx, 19, 34)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) + +let k3 =
{1} {"That is a number"}
; +>k3 : Symbol(k3, Decl(file.tsx, 20, 3)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(file.tsx, 3, 30)) + +let k4 = ; +>k4 : Symbol(k4, Decl(file.tsx, 21, 3)) +>Button : Symbol(Button, Decl(file.tsx, 8, 1)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(file.tsx, 4, 11)) +>Button : Symbol(Button, Decl(file.tsx, 8, 1)) + diff --git a/tests/baselines/reference/checkJsxChildrenProperty11.types b/tests/baselines/reference/checkJsxChildrenProperty11.types new file mode 100644 index 0000000000000..cee5995b8515e --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty11.types @@ -0,0 +1,89 @@ +=== tests/cases/conformance/jsx/file.tsx === +declare module JSX { +>JSX : any + + interface Element { } +>Element : Element + + interface ElementAttributesProperty { props: {} } +>ElementAttributesProperty : ElementAttributesProperty +>props : {} + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + div: any; +>div : any + + h2: any; +>h2 : any + + h1: any; +>h1 : any + } +} + +class Button { +>Button : Button + + props: {} +>props : {} + + render() { +>render : () => JSX.Element + + return (
My Button
) +>(
My Button
) : JSX.Element +>
My Button
: JSX.Element +>div : any +>div : any + } +} + +// OK +let k1 =

Hello

world

; +>k1 : JSX.Element +>

Hello

world

: JSX.Element +>div : any +>

Hello

: JSX.Element +>h2 : any +>h2 : any +>

world

: JSX.Element +>h1 : any +>h1 : any +>div : any + +let k2 =

Hello

{(user: any) =>

{user.name}

}
; +>k2 : JSX.Element +>

Hello

{(user: any) =>

{user.name}

}
: JSX.Element +>div : any +>

Hello

: JSX.Element +>h2 : any +>h2 : any +>(user: any) =>

{user.name}

: (user: any) => JSX.Element +>user : any +>

{user.name}

: JSX.Element +>h2 : any +>user.name : any +>user : any +>name : any +>h2 : any +>div : any + +let k3 =
{1} {"That is a number"}
; +>k3 : JSX.Element +>
{1} {"That is a number"}
: JSX.Element +>div : any +>1 : 1 +>"That is a number" : "That is a number" +>div : any + +let k4 = ; +>k4 : JSX.Element +> : JSX.Element +>Button : typeof Button +>

Hello

: JSX.Element +>h2 : any +>h2 : any +>Button : typeof Button + diff --git a/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt new file mode 100644 index 0000000000000..6bb91bd638501 --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt @@ -0,0 +1,120 @@ +tests/cases/conformance/jsx/file.tsx(14,15): error TS2322: Type '{ a: 10; b: "hi"; }' is not assignable to type 'IntrinsicAttributes & Prop'. + Type '{ a: 10; b: "hi"; }' is not assignable to type 'Prop'. + Property 'children' is missing in type '{ a: 10; b: "hi"; }'. +tests/cases/conformance/jsx/file.tsx(17,11): error TS2710: 'children' are specified twice. The attribute named 'children' will be overwritten. +tests/cases/conformance/jsx/file.tsx(25,11): error TS2710: 'children' are specified twice. The attribute named 'children' will be overwritten. +tests/cases/conformance/jsx/file.tsx(31,11): error TS2322: Type '{ a: 10; b: "hi"; children: (Element | ((name: string) => Element))[]; }' is not assignable to type 'IntrinsicAttributes & Prop'. + Type '{ a: 10; b: "hi"; children: (Element | ((name: string) => Element))[]; }' is not assignable to type 'Prop'. + Types of property 'children' are incompatible. + Type '(Element | ((name: string) => Element))[]' is not assignable to type 'string | Element'. + Type '(Element | ((name: string) => Element))[]' is not assignable to type 'Element'. + Property 'type' is missing in type '(Element | ((name: string) => Element))[]'. +tests/cases/conformance/jsx/file.tsx(37,11): error TS2322: Type '{ a: 10; b: "hi"; children: (Element | 1000000)[]; }' is not assignable to type 'IntrinsicAttributes & Prop'. + Type '{ a: 10; b: "hi"; children: (Element | 1000000)[]; }' is not assignable to type 'Prop'. + Types of property 'children' are incompatible. + Type '(Element | 1000000)[]' is not assignable to type 'string | Element'. + Type '(Element | 1000000)[]' is not assignable to type 'Element'. + Property 'type' is missing in type '(Element | 1000000)[]'. +tests/cases/conformance/jsx/file.tsx(43,11): error TS2322: Type '{ a: 10; b: "hi"; children: (string | Element)[]; }' is not assignable to type 'IntrinsicAttributes & Prop'. + Type '{ a: 10; b: "hi"; children: (string | Element)[]; }' is not assignable to type 'Prop'. + Types of property 'children' are incompatible. + Type '(string | Element)[]' is not assignable to type 'string | Element'. + Type '(string | Element)[]' is not assignable to type 'Element'. + Property 'type' is missing in type '(string | Element)[]'. +tests/cases/conformance/jsx/file.tsx(49,11): error TS2322: Type '{ a: 10; b: "hi"; children: Element[]; }' is not assignable to type 'IntrinsicAttributes & Prop'. + Type '{ a: 10; b: "hi"; children: Element[]; }' is not assignable to type 'Prop'. + Types of property 'children' are incompatible. + Type 'Element[]' is not assignable to type 'string | Element'. + Type 'Element[]' is not assignable to type 'Element'. + Property 'type' is missing in type 'Element[]'. + + +==== tests/cases/conformance/jsx/file.tsx (7 errors) ==== + import React = require('react'); + + interface Prop { + a: number, + b: string, + children: string | JSX.Element + } + + function Comp(p: Prop) { + return
{p.b}
; + } + + // Error: missing children + let k = ; + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: 10; b: "hi"; }' is not assignable to type 'IntrinsicAttributes & Prop'. +!!! error TS2322: Type '{ a: 10; b: "hi"; }' is not assignable to type 'Prop'. +!!! error TS2322: Property 'children' is missing in type '{ a: 10; b: "hi"; }'. + + let k0 = + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2710: 'children' are specified twice. The attribute named 'children' will be overwritten. + hi hi hi! + ; + + let o = { + children:"Random" + } + let k1 = + + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2710: 'children' are specified twice. The attribute named 'children' will be overwritten. + hi hi hi! + ; + + // Error: incorrect type + let k2 = + + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: 10; b: "hi"; children: (Element | ((name: string) => Element))[]; }' is not assignable to type 'IntrinsicAttributes & Prop'. +!!! error TS2322: Type '{ a: 10; b: "hi"; children: (Element | ((name: string) => Element))[]; }' is not assignable to type 'Prop'. +!!! error TS2322: Types of property 'children' are incompatible. +!!! error TS2322: Type '(Element | ((name: string) => Element))[]' is not assignable to type 'string | Element'. +!!! error TS2322: Type '(Element | ((name: string) => Element))[]' is not assignable to type 'Element'. +!!! error TS2322: Property 'type' is missing in type '(Element | ((name: string) => Element))[]'. +
My Div
+ {(name: string) =>
My name {name}
} +
; + + let k3 = + + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: 10; b: "hi"; children: (Element | 1000000)[]; }' is not assignable to type 'IntrinsicAttributes & Prop'. +!!! error TS2322: Type '{ a: 10; b: "hi"; children: (Element | 1000000)[]; }' is not assignable to type 'Prop'. +!!! error TS2322: Types of property 'children' are incompatible. +!!! error TS2322: Type '(Element | 1000000)[]' is not assignable to type 'string | Element'. +!!! error TS2322: Type '(Element | 1000000)[]' is not assignable to type 'Element'. +!!! error TS2322: Property 'type' is missing in type '(Element | 1000000)[]'. +
My Div
+ {1000000} +
; + + let k4 = + + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: 10; b: "hi"; children: (string | Element)[]; }' is not assignable to type 'IntrinsicAttributes & Prop'. +!!! error TS2322: Type '{ a: 10; b: "hi"; children: (string | Element)[]; }' is not assignable to type 'Prop'. +!!! error TS2322: Types of property 'children' are incompatible. +!!! error TS2322: Type '(string | Element)[]' is not assignable to type 'string | Element'. +!!! error TS2322: Type '(string | Element)[]' is not assignable to type 'Element'. +!!! error TS2322: Property 'type' is missing in type '(string | Element)[]'. +
My Div
+ hi hi hi! +
; + + let k5 = + + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: 10; b: "hi"; children: Element[]; }' is not assignable to type 'IntrinsicAttributes & Prop'. +!!! error TS2322: Type '{ a: 10; b: "hi"; children: Element[]; }' is not assignable to type 'Prop'. +!!! error TS2322: Types of property 'children' are incompatible. +!!! error TS2322: Type 'Element[]' is not assignable to type 'string | Element'. +!!! error TS2322: Type 'Element[]' is not assignable to type 'Element'. +!!! error TS2322: Property 'type' is missing in type 'Element[]'. +
My Div
+
My Div
+
; \ No newline at end of file diff --git a/tests/baselines/reference/checkJsxChildrenProperty2.js b/tests/baselines/reference/checkJsxChildrenProperty2.js new file mode 100644 index 0000000000000..dd92bb5dba899 --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty2.js @@ -0,0 +1,89 @@ +//// [file.tsx] +import React = require('react'); + +interface Prop { + a: number, + b: string, + children: string | JSX.Element +} + +function Comp(p: Prop) { + return
{p.b}
; +} + +// Error: missing children +let k = ; + +let k0 = + + hi hi hi! + ; + +let o = { + children:"Random" +} +let k1 = + + hi hi hi! + ; + +// Error: incorrect type +let k2 = + +
My Div
+ {(name: string) =>
My name {name}
} +
; + +let k3 = + +
My Div
+ {1000000} +
; + +let k4 = + +
My Div
+ hi hi hi! +
; + +let k5 = + +
My Div
+
My Div
+
; + +//// [file.jsx] +"use strict"; +exports.__esModule = true; +var React = require("react"); +function Comp(p) { + return
{p.b}
; +} +// Error: missing children +var k = ; +var k0 = + hi hi hi! + ; +var o = { + children: "Random" +}; +var k1 = + hi hi hi! + ; +// Error: incorrect type +var k2 = +
My Div
+ {function (name) { return
My name {name}
; }} +
; +var k3 = +
My Div
+ {1000000} +
; +var k4 = +
My Div
+ hi hi hi! +
; +var k5 = +
My Div
+
My Div
+
; diff --git a/tests/baselines/reference/checkJsxChildrenProperty3.js b/tests/baselines/reference/checkJsxChildrenProperty3.js new file mode 100644 index 0000000000000..49247925523d0 --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty3.js @@ -0,0 +1,79 @@ +//// [file.tsx] +import React = require('react'); + +interface IUser { + Name: string; +} + +interface IFetchUserProps { + children: (user: IUser) => JSX.Element; +} + +class FetchUser extends React.Component { + render() { + return this.state + ? this.props.children(this.state.result) + : null; + } +} + +// Ok +function UserName0() { + return ( + + { user => ( +

{ user.Name }

+ ) } +
+ ); +} + +function UserName1() { + return ( + + + { user => ( +

{ user.Name }

+ ) } +
+ ); +} + +//// [file.jsx] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +var React = require("react"); +var FetchUser = (function (_super) { + __extends(FetchUser, _super); + function FetchUser() { + return _super !== null && _super.apply(this, arguments) || this; + } + FetchUser.prototype.render = function () { + return this.state + ? this.props.children(this.state.result) + : null; + }; + return FetchUser; +}(React.Component)); +// Ok +function UserName0() { + return ( + {function (user) { return (

{user.Name}

); }} +
); +} +function UserName1() { + return ( + + {function (user) { return (

{user.Name}

); }} +
); +} diff --git a/tests/baselines/reference/checkJsxChildrenProperty3.symbols b/tests/baselines/reference/checkJsxChildrenProperty3.symbols new file mode 100644 index 0000000000000..49d146f07dac4 --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty3.symbols @@ -0,0 +1,99 @@ +=== tests/cases/conformance/jsx/file.tsx === +import React = require('react'); +>React : Symbol(React, Decl(file.tsx, 0, 0)) + +interface IUser { +>IUser : Symbol(IUser, Decl(file.tsx, 0, 32)) + + Name: string; +>Name : Symbol(IUser.Name, Decl(file.tsx, 2, 17)) +} + +interface IFetchUserProps { +>IFetchUserProps : Symbol(IFetchUserProps, Decl(file.tsx, 4, 1)) + + children: (user: IUser) => JSX.Element; +>children : Symbol(IFetchUserProps.children, Decl(file.tsx, 6, 27)) +>user : Symbol(user, Decl(file.tsx, 7, 15)) +>IUser : Symbol(IUser, Decl(file.tsx, 0, 32)) +>JSX : Symbol(JSX, Decl(react.d.ts, 2352, 1)) +>Element : Symbol(JSX.Element, Decl(react.d.ts, 2355, 27)) +} + +class FetchUser extends React.Component { +>FetchUser : Symbol(FetchUser, Decl(file.tsx, 8, 1)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>React : Symbol(React, Decl(file.tsx, 0, 0)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>IFetchUserProps : Symbol(IFetchUserProps, Decl(file.tsx, 4, 1)) + + render() { +>render : Symbol(FetchUser.render, Decl(file.tsx, 10, 63)) + + return this.state +>this.state : Symbol(React.Component.state, Decl(react.d.ts, 173, 44)) +>this : Symbol(FetchUser, Decl(file.tsx, 8, 1)) +>state : Symbol(React.Component.state, Decl(react.d.ts, 173, 44)) + + ? this.props.children(this.state.result) +>this.props.children : Symbol(children, Decl(file.tsx, 6, 27), Decl(react.d.ts, 173, 20)) +>this.props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37)) +>this : Symbol(FetchUser, Decl(file.tsx, 8, 1)) +>props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37)) +>children : Symbol(children, Decl(file.tsx, 6, 27), Decl(react.d.ts, 173, 20)) +>this.state : Symbol(React.Component.state, Decl(react.d.ts, 173, 44)) +>this : Symbol(FetchUser, Decl(file.tsx, 8, 1)) +>state : Symbol(React.Component.state, Decl(react.d.ts, 173, 44)) + + : null; + } +} + +// Ok +function UserName0() { +>UserName0 : Symbol(UserName0, Decl(file.tsx, 16, 1)) + + return ( + +>FetchUser : Symbol(FetchUser, Decl(file.tsx, 8, 1)) + + { user => ( +>user : Symbol(user, Decl(file.tsx, 22, 13)) + +

{ user.Name }

+>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) +>user.Name : Symbol(IUser.Name, Decl(file.tsx, 2, 17)) +>user : Symbol(user, Decl(file.tsx, 22, 13)) +>Name : Symbol(IUser.Name, Decl(file.tsx, 2, 17)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) + + ) } +
+>FetchUser : Symbol(FetchUser, Decl(file.tsx, 8, 1)) + + ); +} + +function UserName1() { +>UserName1 : Symbol(UserName1, Decl(file.tsx, 27, 1)) + + return ( + +>FetchUser : Symbol(FetchUser, Decl(file.tsx, 8, 1)) + + { user => ( +>user : Symbol(user, Decl(file.tsx, 33, 13)) + +

{ user.Name }

+>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) +>user.Name : Symbol(IUser.Name, Decl(file.tsx, 2, 17)) +>user : Symbol(user, Decl(file.tsx, 33, 13)) +>Name : Symbol(IUser.Name, Decl(file.tsx, 2, 17)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) + + ) } +
+>FetchUser : Symbol(FetchUser, Decl(file.tsx, 8, 1)) + + ); +} diff --git a/tests/baselines/reference/checkJsxChildrenProperty3.types b/tests/baselines/reference/checkJsxChildrenProperty3.types new file mode 100644 index 0000000000000..7fbb91bee0055 --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty3.types @@ -0,0 +1,116 @@ +=== tests/cases/conformance/jsx/file.tsx === +import React = require('react'); +>React : typeof React + +interface IUser { +>IUser : IUser + + Name: string; +>Name : string +} + +interface IFetchUserProps { +>IFetchUserProps : IFetchUserProps + + children: (user: IUser) => JSX.Element; +>children : (user: IUser) => JSX.Element +>user : IUser +>IUser : IUser +>JSX : any +>Element : JSX.Element +} + +class FetchUser extends React.Component { +>FetchUser : FetchUser +>React.Component : React.Component +>React : typeof React +>Component : typeof React.Component +>IFetchUserProps : IFetchUserProps + + render() { +>render : () => JSX.Element + + return this.state +>this.state ? this.props.children(this.state.result) : null : JSX.Element +>this.state : any +>this : this +>state : any + + ? this.props.children(this.state.result) +>this.props.children(this.state.result) : JSX.Element +>this.props.children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | any[] | React.ReactElement)[]) +>this.props : IFetchUserProps & { children?: React.ReactNode; } +>this : this +>props : IFetchUserProps & { children?: React.ReactNode; } +>children : ((user: IUser) => JSX.Element) | (((user: IUser) => JSX.Element) & string) | (((user: IUser) => JSX.Element) & number) | (((user: IUser) => JSX.Element) & true) | (((user: IUser) => JSX.Element) & false) | (((user: IUser) => JSX.Element) & React.ReactElement) | (((user: IUser) => JSX.Element) & (string | number | boolean | any[] | React.ReactElement)[]) +>this.state.result : any +>this.state : any +>this : this +>state : any +>result : any + + : null; +>null : null + } +} + +// Ok +function UserName0() { +>UserName0 : () => JSX.Element + + return ( +>( { user => (

{ user.Name }

) }
) : JSX.Element + + +> { user => (

{ user.Name }

) }
: JSX.Element +>FetchUser : typeof FetchUser + + { user => ( +>user => (

{ user.Name }

) : (user: IUser) => JSX.Element +>user : IUser +>(

{ user.Name }

) : JSX.Element + +

{ user.Name }

+>

{ user.Name }

: JSX.Element +>h1 : any +>user.Name : string +>user : IUser +>Name : string +>h1 : any + + ) } +
+>FetchUser : typeof FetchUser + + ); +} + +function UserName1() { +>UserName1 : () => JSX.Element + + return ( +>( { user => (

{ user.Name }

) }
) : JSX.Element + + +> { user => (

{ user.Name }

) }
: JSX.Element +>FetchUser : typeof FetchUser + + { user => ( +>user => (

{ user.Name }

) : (user: IUser) => JSX.Element +>user : IUser +>(

{ user.Name }

) : JSX.Element + +

{ user.Name }

+>

{ user.Name }

: JSX.Element +>h1 : any +>user.Name : string +>user : IUser +>Name : string +>h1 : any + + ) } +
+>FetchUser : typeof FetchUser + + ); +} diff --git a/tests/baselines/reference/checkJsxChildrenProperty4.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty4.errors.txt new file mode 100644 index 0000000000000..d12c557102c33 --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty4.errors.txt @@ -0,0 +1,61 @@ +tests/cases/conformance/jsx/file.tsx(24,28): error TS2339: Property 'NAme' does not exist on type 'IUser'. +tests/cases/conformance/jsx/file.tsx(32,9): error TS2322: Type '{ children: ((user: IUser) => Element)[]; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & IFetchUserProps & { children?: ReactNode; }'. + Type '{ children: ((user: IUser) => Element)[]; }' is not assignable to type 'IFetchUserProps'. + Types of property 'children' are incompatible. + Type '((user: IUser) => Element)[]' is not assignable to type '(user: IUser) => Element'. + Type '((user: IUser) => Element)[]' provides no match for the signature '(user: IUser): Element'. + + +==== tests/cases/conformance/jsx/file.tsx (2 errors) ==== + import React = require('react'); + + interface IUser { + Name: string; + } + + interface IFetchUserProps { + children: (user: IUser) => JSX.Element; + } + + class FetchUser extends React.Component { + render() { + return this.state + ? this.props.children(this.state.result) + : null; + } + } + + // Error + function UserName() { + return ( + + { user => ( +

{ user.NAme }

+ ~~~~ +!!! error TS2339: Property 'NAme' does not exist on type 'IUser'. + ) } +
+ ); + } + + function UserName1() { + return ( + + ~~~~~~~~~~~ +!!! error TS2322: Type '{ children: ((user: IUser) => Element)[]; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & IFetchUserProps & { children?: ReactNode; }'. +!!! error TS2322: Type '{ children: ((user: IUser) => Element)[]; }' is not assignable to type 'IFetchUserProps'. +!!! error TS2322: Types of property 'children' are incompatible. +!!! error TS2322: Type '((user: IUser) => Element)[]' is not assignable to type '(user: IUser) => Element'. +!!! error TS2322: Type '((user: IUser) => Element)[]' provides no match for the signature '(user: IUser): Element'. + + + + { user => ( +

{ user.Name }

+ ) } + { user => ( +

{ user.Name }

+ ) } +
+ ); + } \ No newline at end of file diff --git a/tests/baselines/reference/checkJsxChildrenProperty4.js b/tests/baselines/reference/checkJsxChildrenProperty4.js new file mode 100644 index 0000000000000..d163ffb0f41b5 --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty4.js @@ -0,0 +1,87 @@ +//// [file.tsx] +import React = require('react'); + +interface IUser { + Name: string; +} + +interface IFetchUserProps { + children: (user: IUser) => JSX.Element; +} + +class FetchUser extends React.Component { + render() { + return this.state + ? this.props.children(this.state.result) + : null; + } +} + +// Error +function UserName() { + return ( + + { user => ( +

{ user.NAme }

+ ) } +
+ ); +} + +function UserName1() { + return ( + + + + + { user => ( +

{ user.Name }

+ ) } + { user => ( +

{ user.Name }

+ ) } +
+ ); +} + +//// [file.jsx] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +var React = require("react"); +var FetchUser = (function (_super) { + __extends(FetchUser, _super); + function FetchUser() { + return _super !== null && _super.apply(this, arguments) || this; + } + FetchUser.prototype.render = function () { + return this.state + ? this.props.children(this.state.result) + : null; + }; + return FetchUser; +}(React.Component)); +// Error +function UserName() { + return ( + {function (user) { return (

{user.NAme}

); }} +
); +} +function UserName1() { + return ( + + + + {function (user) { return (

{user.Name}

); }} + {function (user) { return (

{user.Name}

); }} +
); +} diff --git a/tests/baselines/reference/checkJsxChildrenProperty5.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty5.errors.txt new file mode 100644 index 0000000000000..1890bc732d1af --- /dev/null +++ b/tests/baselines/reference/checkJsxChildrenProperty5.errors.txt @@ -0,0 +1,62 @@ +tests/cases/conformance/jsx/file.tsx(20,15): error TS2322: Type '{ a: 10; b: "hi"; }' is not assignable to type 'IntrinsicAttributes & Prop'. + Type '{ a: 10; b: "hi"; }' is not assignable to type 'Prop'. + Property 'children' is missing in type '{ a: 10; b: "hi"; }'. +tests/cases/conformance/jsx/file.tsx(24,11): error TS2322: Type '{ a: 10; b: "hi"; children: Element; }' is not assignable to type 'IntrinsicAttributes & Prop'. + Type '{ a: 10; b: "hi"; children: Element; }' is not assignable to type 'Prop'. + Types of property 'children' are incompatible. + Type 'Element' is not assignable to type 'Button'. + Property 'render' is missing in type 'Element'. +tests/cases/conformance/jsx/file.tsx(28,11): error TS2322: Type '{ a: 10; b: "hi"; children: typeof Button; }' is not assignable to type 'IntrinsicAttributes & Prop'. + Type '{ a: 10; b: "hi"; children: typeof Button; }' is not assignable to type 'Prop'. + Types of property 'children' are incompatible. + Type 'typeof Button' is not assignable to type 'Button'. + Property 'render' is missing in type 'typeof Button'. + + +==== tests/cases/conformance/jsx/file.tsx (3 errors) ==== + import React = require('react'); + + interface Prop { + a: number, + b: string, + children: Button; + } + + class Button extends React.Component { + render() { + return (
My Button
) + } + } + + function Comp(p: Prop) { + return
{p.b}
; + } + + // Error: no children specified + let k = ; + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: 10; b: "hi"; }' is not assignable to type 'IntrinsicAttributes & Prop'. +!!! error TS2322: Type '{ a: 10; b: "hi"; }' is not assignable to type 'Prop'. +!!! error TS2322: Property 'children' is missing in type '{ a: 10; b: "hi"; }'. + + // Error: JSX.element is not the same as JSX.ElementClass + let k1 = + + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: 10; b: "hi"; children: Element; }' is not assignable to type 'IntrinsicAttributes & Prop'. +!!! error TS2322: Type '{ a: 10; b: "hi"; children: Element; }' is not assignable to type 'Prop'. +!!! error TS2322: Types of property 'children' are incompatible. +!!! error TS2322: Type 'Element' is not assignable to type 'Button'. +!!! error TS2322: Property 'render' is missing in type 'Element'. + }/> >MyComponent : Symbol(MyComponent, Decl(file.tsx, 4, 1)) >AnyComponent : Symbol(AnyComponent, Decl(file.tsx, 14, 12)) ->button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2383, 43)) ->button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2383, 43)) +>button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2385, 43)) +>button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2385, 43)) // Component Class as Props class MyButtonComponent extends React.Component<{},{}> { diff --git a/tests/cases/conformance/jsx/checkJsxChildrenProperty1.tsx b/tests/cases/conformance/jsx/checkJsxChildrenProperty1.tsx new file mode 100644 index 0000000000000..70b58c03f6ac1 --- /dev/null +++ b/tests/cases/conformance/jsx/checkJsxChildrenProperty1.tsx @@ -0,0 +1,27 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +interface Prop { + a: number, + b: string, + children: string | JSX.Element +} + +function Comp(p: Prop) { + return
{p.b}
; +} + +// OK +let k = ; +let k1 = + + hi hi hi! + ; +let k2 = + +
hi hi hi!
+
; \ No newline at end of file diff --git a/tests/cases/conformance/jsx/checkJsxChildrenProperty10.tsx b/tests/cases/conformance/jsx/checkJsxChildrenProperty10.tsx new file mode 100644 index 0000000000000..f13f44567ffb4 --- /dev/null +++ b/tests/cases/conformance/jsx/checkJsxChildrenProperty10.tsx @@ -0,0 +1,24 @@ +//@filename: file.tsx +//@jsx: preserve +declare module JSX { + interface Element { } + interface ElementAttributesProperty { props: {} } + interface IntrinsicElements { + div: any; + h2: any; + h1: any; + } +} + +class Button { + props: {} + render() { + return (
My Button
) + } +} + +// OK +let k1 =

Hello

world

; +let k2 =

Hello

{(user: any) =>

{user.name}

}
; +let k3 =
{1} {"That is a number"}
; +let k4 = ; \ No newline at end of file diff --git a/tests/cases/conformance/jsx/checkJsxChildrenProperty11.tsx b/tests/cases/conformance/jsx/checkJsxChildrenProperty11.tsx new file mode 100644 index 0000000000000..a6fab6f506e66 --- /dev/null +++ b/tests/cases/conformance/jsx/checkJsxChildrenProperty11.tsx @@ -0,0 +1,25 @@ +//@filename: file.tsx +//@jsx: preserve +//@noImplicitAny: true +declare module JSX { + interface Element { } + interface ElementAttributesProperty { props: {} } + interface IntrinsicElements { + div: any; + h2: any; + h1: any; + } +} + +class Button { + props: {} + render() { + return (
My Button
) + } +} + +// OK +let k1 =

Hello

world

; +let k2 =

Hello

{(user: any) =>

{user.name}

}
; +let k3 =
{1} {"That is a number"}
; +let k4 = ; \ No newline at end of file diff --git a/tests/cases/conformance/jsx/checkJsxChildrenProperty2.tsx b/tests/cases/conformance/jsx/checkJsxChildrenProperty2.tsx new file mode 100644 index 0000000000000..65bc0f50b120a --- /dev/null +++ b/tests/cases/conformance/jsx/checkJsxChildrenProperty2.tsx @@ -0,0 +1,57 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +interface Prop { + a: number, + b: string, + children: string | JSX.Element +} + +function Comp(p: Prop) { + return
{p.b}
; +} + +// Error: missing children +let k = ; + +let k0 = + + hi hi hi! + ; + +let o = { + children:"Random" +} +let k1 = + + hi hi hi! + ; + +// Error: incorrect type +let k2 = + +
My Div
+ {(name: string) =>
My name {name}
} +
; + +let k3 = + +
My Div
+ {1000000} +
; + +let k4 = + +
My Div
+ hi hi hi! +
; + +let k5 = + +
My Div
+
My Div
+
; \ No newline at end of file diff --git a/tests/cases/conformance/jsx/checkJsxChildrenProperty3.tsx b/tests/cases/conformance/jsx/checkJsxChildrenProperty3.tsx new file mode 100644 index 0000000000000..c67c6d5440dce --- /dev/null +++ b/tests/cases/conformance/jsx/checkJsxChildrenProperty3.tsx @@ -0,0 +1,44 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +interface IUser { + Name: string; +} + +interface IFetchUserProps { + children: (user: IUser) => JSX.Element; +} + +class FetchUser extends React.Component { + render() { + return this.state + ? this.props.children(this.state.result) + : null; + } +} + +// Ok +function UserName0() { + return ( + + { user => ( +

{ user.Name }

+ ) } +
+ ); +} + +function UserName1() { + return ( + + + { user => ( +

{ user.Name }

+ ) } +
+ ); +} \ No newline at end of file diff --git a/tests/cases/conformance/jsx/checkJsxChildrenProperty4.tsx b/tests/cases/conformance/jsx/checkJsxChildrenProperty4.tsx new file mode 100644 index 0000000000000..34877f2000cd3 --- /dev/null +++ b/tests/cases/conformance/jsx/checkJsxChildrenProperty4.tsx @@ -0,0 +1,49 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +interface IUser { + Name: string; +} + +interface IFetchUserProps { + children: (user: IUser) => JSX.Element; +} + +class FetchUser extends React.Component { + render() { + return this.state + ? this.props.children(this.state.result) + : null; + } +} + +// Error +function UserName() { + return ( + + { user => ( +

{ user.NAme }

+ ) } +
+ ); +} + +function UserName1() { + return ( + + + + + { user => ( +

{ user.Name }

+ ) } + { user => ( +

{ user.Name }

+ ) } +
+ ); +} \ No newline at end of file diff --git a/tests/cases/conformance/jsx/checkJsxChildrenProperty5.tsx b/tests/cases/conformance/jsx/checkJsxChildrenProperty5.tsx new file mode 100644 index 0000000000000..6143e4b0fafa9 --- /dev/null +++ b/tests/cases/conformance/jsx/checkJsxChildrenProperty5.tsx @@ -0,0 +1,35 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +interface Prop { + a: number, + b: string, + children: Button; +} + +class Button extends React.Component { + render() { + return (
My Button
) + } +} + +function Comp(p: Prop) { + return
{p.b}
; +} + +// Error: no children specified +let k = ; + +// Error: JSX.element is not the same as JSX.ElementClass +let k1 = + +