diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3e9a33007261a..c4cd1aa60515b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17361,12 +17361,14 @@ namespace ts { let hasSpreadAnyType = false; let typeToIntersect: Type | undefined; let explicitlySpecifyChildrenAttribute = false; + let propagatingFlags: TypeFlags = 0; const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(openingLikeElement)); for (const attributeDecl of attributes.properties) { const member = attributeDecl.symbol; if (isJsxAttribute(attributeDecl)) { const exprType = checkJsxAttribute(attributeDecl, checkMode); + propagatingFlags |= (exprType.flags & TypeFlags.PropagatingFlags); const attributeSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.escapedName); attributeSymbol.declarations = member.declarations; @@ -17384,7 +17386,7 @@ namespace ts { else { Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute); if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, /*typeFlags*/ 0, ObjectFlags.JsxAttributes); + spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, propagatingFlags, ObjectFlags.JsxAttributes); attributesTable = createSymbolTable(); } const exprType = checkExpressionCached(attributeDecl.expression, checkMode); @@ -17392,7 +17394,7 @@ namespace ts { hasSpreadAnyType = true; } if (isValidSpreadType(exprType)) { - spread = getSpreadType(spread, exprType, openingLikeElement.symbol, /*typeFlags*/ 0, ObjectFlags.JsxAttributes); + spread = getSpreadType(spread, exprType, openingLikeElement.symbol, propagatingFlags, ObjectFlags.JsxAttributes); } else { typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType; @@ -17402,7 +17404,7 @@ namespace ts { if (!hasSpreadAnyType) { if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, /*typeFlags*/ 0, ObjectFlags.JsxAttributes); + spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, propagatingFlags, ObjectFlags.JsxAttributes); } } @@ -17428,7 +17430,7 @@ namespace ts { const childPropMap = createSymbolTable(); childPropMap.set(jsxChildrenPropertyName, childrenPropSymbol); spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined), - attributes.symbol, /*typeFlags*/ 0, ObjectFlags.JsxAttributes); + attributes.symbol, propagatingFlags, ObjectFlags.JsxAttributes); } } @@ -17448,7 +17450,7 @@ namespace ts { */ function createJsxAttributesType() { const result = createAnonymousType(attributes.symbol, attributesTable, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined); - result.flags |= TypeFlags.ContainsObjectLiteral; + result.flags |= (propagatingFlags |= TypeFlags.ContainsObjectLiteral); result.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.JsxAttributes; return result; } @@ -21957,7 +21959,7 @@ namespace ts { } function getContextNode(node: Expression): Node { - if (node.kind === SyntaxKind.JsxAttributes) { + if (node.kind === SyntaxKind.JsxAttributes && !isJsxSelfClosingElement(node.parent)) { return node.parent.parent; // Needs to be the root JsxElement, so it encompasses the attributes _and_ the children (which are essentially part of the attributes) } return node; diff --git a/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.errors.txt b/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.errors.txt index 6b81ccd77e1b7..36ebc70b76ce3 100644 --- a/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.errors.txt +++ b/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.errors.txt @@ -1,5 +1,6 @@ -tests/cases/conformance/jsx/file.tsx(13,54): error TS2322: Type '(a: { x: string; }) => string' is not assignable to type '(cur: { x: string; }) => { x: string; }'. - Type 'string' is not assignable to type '{ x: string; }'. +tests/cases/conformance/jsx/file.tsx(13,54): error TS2322: Type '(a: { x: string; }) => string' is not assignable to type '((a: { x: string; }) => string) & ((cur: { x: string; }) => { x: string; })'. + Type '(a: { x: string; }) => string' is not assignable to type '(cur: { x: string; }) => { x: string; }'. + Type 'string' is not assignable to type '{ x: string; }'. ==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== @@ -17,6 +18,7 @@ tests/cases/conformance/jsx/file.tsx(13,54): error TS2322: Type '(a: { x: string let c = ({ x: a.x })} />; // No Error let d = a.x} />; // Error - `string` is not assignable to `{x: string}` ~~~~~~~~~~ -!!! error TS2322: Type '(a: { x: string; }) => string' is not assignable to type '(cur: { x: string; }) => { x: string; }'. -!!! error TS2322: Type 'string' is not assignable to type '{ x: string; }'. -!!! related TS6500 tests/cases/conformance/jsx/file.tsx:13:54: The expected type comes from property 'nextValues' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes> & { initialValues: { x: string; }; nextValues: {}; } & BaseProps<{ x: string; }> & { children?: ReactNode; }' \ No newline at end of file +!!! error TS2322: Type '(a: { x: string; }) => string' is not assignable to type '((a: { x: string; }) => string) & ((cur: { x: string; }) => { x: string; })'. +!!! error TS2322: Type '(a: { x: string; }) => string' is not assignable to type '(cur: { x: string; }) => { x: string; }'. +!!! error TS2322: Type 'string' is not assignable to type '{ x: string; }'. +!!! related TS6500 tests/cases/conformance/jsx/file.tsx:13:54: The expected type comes from property 'nextValues' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes string; }, { x: string; }>> & { initialValues: { x: string; }; nextValues: (a: { x: string; }) => string; } & BaseProps<{ x: string; }> & { children?: ReactNode; }' \ No newline at end of file diff --git a/tests/baselines/reference/conditionalTypeContextualTypeSimplificationsSuceeds.js b/tests/baselines/reference/conditionalTypeContextualTypeSimplificationsSuceeds.js new file mode 100644 index 0000000000000..7d140a32b423c --- /dev/null +++ b/tests/baselines/reference/conditionalTypeContextualTypeSimplificationsSuceeds.js @@ -0,0 +1,25 @@ +//// [conditionalTypeContextualTypeSimplificationsSuceeds.ts] +// repro from https://github.com/Microsoft/TypeScript/issues/26395 +interface Props { + when: (value: string) => boolean; +} + +function bad

( + attrs: string extends keyof P ? { [K in keyof P]: P[K] } : { [K in keyof P]: P[K] }) { } +function good1

( + attrs: string extends keyof P ? P : { [K in keyof P]: P[K] }) { } +function good2

( + attrs: { [K in keyof P]: P[K] }) { } + +bad({ when: value => false }); +good1({ when: value => false }); +good2({ when: value => false }); + +//// [conditionalTypeContextualTypeSimplificationsSuceeds.js] +"use strict"; +function bad(attrs) { } +function good1(attrs) { } +function good2(attrs) { } +bad({ when: function (value) { return false; } }); +good1({ when: function (value) { return false; } }); +good2({ when: function (value) { return false; } }); diff --git a/tests/baselines/reference/conditionalTypeContextualTypeSimplificationsSuceeds.symbols b/tests/baselines/reference/conditionalTypeContextualTypeSimplificationsSuceeds.symbols new file mode 100644 index 0000000000000..e9620b38656eb --- /dev/null +++ b/tests/baselines/reference/conditionalTypeContextualTypeSimplificationsSuceeds.symbols @@ -0,0 +1,68 @@ +=== tests/cases/compiler/conditionalTypeContextualTypeSimplificationsSuceeds.ts === +// repro from https://github.com/Microsoft/TypeScript/issues/26395 +interface Props { +>Props : Symbol(Props, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 0, 0)) + + when: (value: string) => boolean; +>when : Symbol(Props.when, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 1, 17)) +>value : Symbol(value, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 2, 11)) +} + +function bad

( +>bad : Symbol(bad, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 3, 1)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 5, 13)) +>Props : Symbol(Props, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 0, 0)) + + attrs: string extends keyof P ? { [K in keyof P]: P[K] } : { [K in keyof P]: P[K] }) { } +>attrs : Symbol(attrs, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 5, 30)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 5, 13)) +>K : Symbol(K, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 6, 39)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 5, 13)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 5, 13)) +>K : Symbol(K, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 6, 39)) +>K : Symbol(K, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 6, 66)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 5, 13)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 5, 13)) +>K : Symbol(K, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 6, 66)) + +function good1

( +>good1 : Symbol(good1, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 6, 92)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 7, 15)) +>Props : Symbol(Props, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 0, 0)) + + attrs: string extends keyof P ? P : { [K in keyof P]: P[K] }) { } +>attrs : Symbol(attrs, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 7, 32)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 7, 15)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 7, 15)) +>K : Symbol(K, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 8, 43)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 7, 15)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 7, 15)) +>K : Symbol(K, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 8, 43)) + +function good2

( +>good2 : Symbol(good2, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 8, 69)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 9, 15)) +>Props : Symbol(Props, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 0, 0)) + + attrs: { [K in keyof P]: P[K] }) { } +>attrs : Symbol(attrs, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 9, 32)) +>K : Symbol(K, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 10, 14)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 9, 15)) +>P : Symbol(P, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 9, 15)) +>K : Symbol(K, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 10, 14)) + +bad({ when: value => false }); +>bad : Symbol(bad, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 3, 1)) +>when : Symbol(when, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 12, 5)) +>value : Symbol(value, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 12, 11)) + +good1({ when: value => false }); +>good1 : Symbol(good1, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 6, 92)) +>when : Symbol(when, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 13, 7)) +>value : Symbol(value, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 13, 13)) + +good2({ when: value => false }); +>good2 : Symbol(good2, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 8, 69)) +>when : Symbol(when, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 14, 7)) +>value : Symbol(value, Decl(conditionalTypeContextualTypeSimplificationsSuceeds.ts, 14, 13)) + diff --git a/tests/baselines/reference/conditionalTypeContextualTypeSimplificationsSuceeds.types b/tests/baselines/reference/conditionalTypeContextualTypeSimplificationsSuceeds.types new file mode 100644 index 0000000000000..cf55d7c3bcd3e --- /dev/null +++ b/tests/baselines/reference/conditionalTypeContextualTypeSimplificationsSuceeds.types @@ -0,0 +1,53 @@ +=== tests/cases/compiler/conditionalTypeContextualTypeSimplificationsSuceeds.ts === +// repro from https://github.com/Microsoft/TypeScript/issues/26395 +interface Props { + when: (value: string) => boolean; +>when : (value: string) => boolean +>value : string +} + +function bad

( +>bad :

(attrs: string extends keyof P ? { [K in keyof P]: P[K]; } : { [K in keyof P]: P[K]; }) => void + + attrs: string extends keyof P ? { [K in keyof P]: P[K] } : { [K in keyof P]: P[K] }) { } +>attrs : string extends keyof P ? { [K in keyof P]: P[K]; } : { [K in keyof P]: P[K]; } + +function good1

( +>good1 :

(attrs: string extends keyof P ? P : { [K in keyof P]: P[K]; }) => void + + attrs: string extends keyof P ? P : { [K in keyof P]: P[K] }) { } +>attrs : string extends keyof P ? P : { [K in keyof P]: P[K]; } + +function good2

( +>good2 :

(attrs: { [K in keyof P]: P[K]; }) => void + + attrs: { [K in keyof P]: P[K] }) { } +>attrs : { [K in keyof P]: P[K]; } + +bad({ when: value => false }); +>bad({ when: value => false }) : void +>bad :

(attrs: string extends keyof P ? { [K in keyof P]: P[K]; } : { [K in keyof P]: P[K]; }) => void +>{ when: value => false } : { when: (value: string) => false; } +>when : (value: string) => false +>value => false : (value: string) => false +>value : string +>false : false + +good1({ when: value => false }); +>good1({ when: value => false }) : void +>good1 :

(attrs: string extends keyof P ? P : { [K in keyof P]: P[K]; }) => void +>{ when: value => false } : { when: (value: string) => false; } +>when : (value: string) => false +>value => false : (value: string) => false +>value : string +>false : false + +good2({ when: value => false }); +>good2({ when: value => false }) : void +>good2 :

(attrs: { [K in keyof P]: P[K]; }) => void +>{ when: value => false } : { when: (value: string) => false; } +>when : (value: string) => false +>value => false : (value: string) => false +>value : string +>false : false + diff --git a/tests/baselines/reference/jsxChildrenGenericContextualTypes.errors.txt b/tests/baselines/reference/jsxChildrenGenericContextualTypes.errors.txt index 9c9b85fd04d9f..f9e193d104ba7 100644 --- a/tests/baselines/reference/jsxChildrenGenericContextualTypes.errors.txt +++ b/tests/baselines/reference/jsxChildrenGenericContextualTypes.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx(20,31): error TS2322: Type '(p: IntrinsicAttributes & LitProps<"x">) => "y"' is not assignable to type '(x: IntrinsicAttributes & LitProps<"x">) => "x"'. +tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx(20,31): error TS2322: Type '(p: LitProps<"x">) => "y"' is not assignable to type '(x: IntrinsicAttributes & LitProps<"x">) => "x"'. Type '"y"' is not assignable to type '"x"'. tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx(21,19): error TS2322: Type '{ children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'IntrinsicAttributes & LitProps<"x" | "y">'. Type '{ children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'LitProps<"x" | "y">'. @@ -39,7 +39,7 @@ tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx(22,21): error TS2322: // Should error const arg = "y"} /> ~~~~~~~~ -!!! error TS2322: Type '(p: IntrinsicAttributes & LitProps<"x">) => "y"' is not assignable to type '(x: IntrinsicAttributes & LitProps<"x">) => "x"'. +!!! error TS2322: Type '(p: LitProps<"x">) => "y"' is not assignable to type '(x: IntrinsicAttributes & LitProps<"x">) => "x"'. !!! error TS2322: Type '"y"' is not assignable to type '"x"'. !!! related TS6500 tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx:13:34: The expected type comes from property 'children' which is declared here on type 'IntrinsicAttributes & LitProps<"x">' const argchild = {p => "y"} diff --git a/tests/baselines/reference/jsxChildrenGenericContextualTypes.types b/tests/baselines/reference/jsxChildrenGenericContextualTypes.types index 9287a8a02deed..0e5cf26d4c7c7 100644 --- a/tests/baselines/reference/jsxChildrenGenericContextualTypes.types +++ b/tests/baselines/reference/jsxChildrenGenericContextualTypes.types @@ -117,9 +117,9 @@ const arg = "y"} /> > "y"} /> : JSX.Element >ElemLit : (p: LitProps) => JSX.Element >prop : "x" ->children : (p: JSX.IntrinsicAttributes & LitProps<"x">) => "y" ->p => "y" : (p: JSX.IntrinsicAttributes & LitProps<"x">) => "y" ->p : JSX.IntrinsicAttributes & LitProps<"x"> +>children : (p: LitProps<"x">) => "y" +>p => "y" : (p: LitProps<"x">) => "y" +>p : LitProps<"x"> >"y" : "y" const argchild = {p => "y"} diff --git a/tests/baselines/reference/reactDefaultPropsInferenceSuccess.errors.txt b/tests/baselines/reference/reactDefaultPropsInferenceSuccess.errors.txt new file mode 100644 index 0000000000000..2ec0fc09c9213 --- /dev/null +++ b/tests/baselines/reference/reactDefaultPropsInferenceSuccess.errors.txt @@ -0,0 +1,67 @@ +tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx(26,36): error TS2322: Type '(value: string) => void' is not assignable to type '(value: string) => boolean'. + Type 'void' is not assignable to type 'boolean'. +tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx(48,37): error TS2322: Type '(value: string) => void' is not assignable to type '(value: string) => boolean'. + Type 'void' is not assignable to type 'boolean'. + + +==== tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx (2 errors) ==== + /// + + import React from 'react'; + + interface BaseProps { + when?: (value: string) => boolean; + } + + interface Props extends BaseProps { + } + + class FieldFeedback

extends React.Component

{ + static defaultProps = { + when: () => true + }; + + render() { + return

Hello
; + } + } + + // OK + const Test1 = () => !!value} />; + + // Error: Void not assignable to boolean + const Test2 = () => console.log(value)} />; + ~~~~ +!!! error TS2322: Type '(value: string) => void' is not assignable to type '(value: string) => boolean'. +!!! error TS2322: Type 'void' is not assignable to type 'boolean'. +!!! related TS6500 tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx:6:3: The expected type comes from property 'when' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes> & Pick & Readonly, "children"> & Partial & Readonly, "when">> & Partial boolean; }, never>>' + + + interface MyPropsProps extends Props { + when: (value: string) => boolean; + } + + class FieldFeedback2

extends FieldFeedback

{ + static defaultProps = { + when: () => true + }; + + render() { + this.props.when("now"); // OK, always defined + return

Hello
; + } + } + + // OK + const Test3 = () => !!value} />; + + // Error: Void not assignable to boolean + const Test4 = () => console.log(value)} />; + ~~~~ +!!! error TS2322: Type '(value: string) => void' is not assignable to type '(value: string) => boolean'. +!!! error TS2322: Type 'void' is not assignable to type 'boolean'. +!!! related TS6500 tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx:30:3: The expected type comes from property 'when' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes> & Pick & Readonly, "children"> & Partial & Readonly, "when">> & Partial boolean; }, never>>' + + // OK + const Test5 = () => ; + \ No newline at end of file diff --git a/tests/baselines/reference/reactDefaultPropsInferenceSuccess.js b/tests/baselines/reference/reactDefaultPropsInferenceSuccess.js new file mode 100644 index 0000000000000..84db36ee4da06 --- /dev/null +++ b/tests/baselines/reference/reactDefaultPropsInferenceSuccess.js @@ -0,0 +1,112 @@ +//// [reactDefaultPropsInferenceSuccess.tsx] +/// + +import React from 'react'; + +interface BaseProps { + when?: (value: string) => boolean; +} + +interface Props extends BaseProps { +} + +class FieldFeedback

extends React.Component

{ + static defaultProps = { + when: () => true + }; + + render() { + return

Hello
; + } +} + +// OK +const Test1 = () => !!value} />; + +// Error: Void not assignable to boolean +const Test2 = () => console.log(value)} />; + + +interface MyPropsProps extends Props { + when: (value: string) => boolean; +} + +class FieldFeedback2

extends FieldFeedback

{ + static defaultProps = { + when: () => true + }; + + render() { + this.props.when("now"); // OK, always defined + return

Hello
; + } +} + +// OK +const Test3 = () => !!value} />; + +// Error: Void not assignable to boolean +const Test4 = () => console.log(value)} />; + +// OK +const Test5 = () => ; + + +//// [reactDefaultPropsInferenceSuccess.js] +"use strict"; +/// +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + 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 extendStatics(d, b); + } + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +exports.__esModule = true; +var react_1 = __importDefault(require("react")); +var FieldFeedback = /** @class */ (function (_super) { + __extends(FieldFeedback, _super); + function FieldFeedback() { + return _super !== null && _super.apply(this, arguments) || this; + } + FieldFeedback.prototype.render = function () { + return react_1["default"].createElement("div", null, "Hello"); + }; + FieldFeedback.defaultProps = { + when: function () { return true; } + }; + return FieldFeedback; +}(react_1["default"].Component)); +// OK +var Test1 = function () { return react_1["default"].createElement(FieldFeedback, { when: function (value) { return !!value; } }); }; +// Error: Void not assignable to boolean +var Test2 = function () { return react_1["default"].createElement(FieldFeedback, { when: function (value) { return console.log(value); } }); }; +var FieldFeedback2 = /** @class */ (function (_super) { + __extends(FieldFeedback2, _super); + function FieldFeedback2() { + return _super !== null && _super.apply(this, arguments) || this; + } + FieldFeedback2.prototype.render = function () { + this.props.when("now"); // OK, always defined + return react_1["default"].createElement("div", null, "Hello"); + }; + FieldFeedback2.defaultProps = { + when: function () { return true; } + }; + return FieldFeedback2; +}(FieldFeedback)); +// OK +var Test3 = function () { return react_1["default"].createElement(FieldFeedback2, { when: function (value) { return !!value; } }); }; +// Error: Void not assignable to boolean +var Test4 = function () { return react_1["default"].createElement(FieldFeedback2, { when: function (value) { return console.log(value); } }); }; +// OK +var Test5 = function () { return react_1["default"].createElement(FieldFeedback2, null); }; diff --git a/tests/baselines/reference/reactDefaultPropsInferenceSuccess.symbols b/tests/baselines/reference/reactDefaultPropsInferenceSuccess.symbols new file mode 100644 index 0000000000000..dadaf9ea74520 --- /dev/null +++ b/tests/baselines/reference/reactDefaultPropsInferenceSuccess.symbols @@ -0,0 +1,131 @@ +=== tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx === +/// + +import React from 'react'; +>React : Symbol(React, Decl(reactDefaultPropsInferenceSuccess.tsx, 2, 6)) + +interface BaseProps { +>BaseProps : Symbol(BaseProps, Decl(reactDefaultPropsInferenceSuccess.tsx, 2, 26)) + + when?: (value: string) => boolean; +>when : Symbol(BaseProps.when, Decl(reactDefaultPropsInferenceSuccess.tsx, 4, 21)) +>value : Symbol(value, Decl(reactDefaultPropsInferenceSuccess.tsx, 5, 10)) +} + +interface Props extends BaseProps { +>Props : Symbol(Props, Decl(reactDefaultPropsInferenceSuccess.tsx, 6, 1)) +>BaseProps : Symbol(BaseProps, Decl(reactDefaultPropsInferenceSuccess.tsx, 2, 26)) +} + +class FieldFeedback

extends React.Component

{ +>FieldFeedback : Symbol(FieldFeedback, Decl(reactDefaultPropsInferenceSuccess.tsx, 9, 1)) +>P : Symbol(P, Decl(reactDefaultPropsInferenceSuccess.tsx, 11, 20)) +>Props : Symbol(Props, Decl(reactDefaultPropsInferenceSuccess.tsx, 6, 1)) +>BaseProps : Symbol(BaseProps, Decl(reactDefaultPropsInferenceSuccess.tsx, 2, 26)) +>React.Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94)) +>React : Symbol(React, Decl(reactDefaultPropsInferenceSuccess.tsx, 2, 6)) +>Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94)) +>P : Symbol(P, Decl(reactDefaultPropsInferenceSuccess.tsx, 11, 20)) + + static defaultProps = { +>defaultProps : Symbol(FieldFeedback.defaultProps, Decl(reactDefaultPropsInferenceSuccess.tsx, 11, 77)) + + when: () => true +>when : Symbol(when, Decl(reactDefaultPropsInferenceSuccess.tsx, 12, 25)) + + }; + + render() { +>render : Symbol(FieldFeedback.render, Decl(reactDefaultPropsInferenceSuccess.tsx, 14, 4)) + + return

Hello
; +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114)) + } +} + +// OK +const Test1 = () => !!value} />; +>Test1 : Symbol(Test1, Decl(reactDefaultPropsInferenceSuccess.tsx, 22, 5)) +>FieldFeedback : Symbol(FieldFeedback, Decl(reactDefaultPropsInferenceSuccess.tsx, 9, 1)) +>when : Symbol(when, Decl(reactDefaultPropsInferenceSuccess.tsx, 22, 34)) +>value : Symbol(value, Decl(reactDefaultPropsInferenceSuccess.tsx, 22, 41)) +>value : Symbol(value, Decl(reactDefaultPropsInferenceSuccess.tsx, 22, 41)) + +// Error: Void not assignable to boolean +const Test2 = () => console.log(value)} />; +>Test2 : Symbol(Test2, Decl(reactDefaultPropsInferenceSuccess.tsx, 25, 5)) +>FieldFeedback : Symbol(FieldFeedback, Decl(reactDefaultPropsInferenceSuccess.tsx, 9, 1)) +>when : Symbol(when, Decl(reactDefaultPropsInferenceSuccess.tsx, 25, 34)) +>value : Symbol(value, Decl(reactDefaultPropsInferenceSuccess.tsx, 25, 41)) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>value : Symbol(value, Decl(reactDefaultPropsInferenceSuccess.tsx, 25, 41)) + + +interface MyPropsProps extends Props { +>MyPropsProps : Symbol(MyPropsProps, Decl(reactDefaultPropsInferenceSuccess.tsx, 25, 73)) +>Props : Symbol(Props, Decl(reactDefaultPropsInferenceSuccess.tsx, 6, 1)) + + when: (value: string) => boolean; +>when : Symbol(MyPropsProps.when, Decl(reactDefaultPropsInferenceSuccess.tsx, 28, 38)) +>value : Symbol(value, Decl(reactDefaultPropsInferenceSuccess.tsx, 29, 9)) +} + +class FieldFeedback2

extends FieldFeedback

{ +>FieldFeedback2 : Symbol(FieldFeedback2, Decl(reactDefaultPropsInferenceSuccess.tsx, 30, 1)) +>P : Symbol(P, Decl(reactDefaultPropsInferenceSuccess.tsx, 32, 21)) +>MyPropsProps : Symbol(MyPropsProps, Decl(reactDefaultPropsInferenceSuccess.tsx, 25, 73)) +>MyPropsProps : Symbol(MyPropsProps, Decl(reactDefaultPropsInferenceSuccess.tsx, 25, 73)) +>FieldFeedback : Symbol(FieldFeedback, Decl(reactDefaultPropsInferenceSuccess.tsx, 9, 1)) +>P : Symbol(P, Decl(reactDefaultPropsInferenceSuccess.tsx, 32, 21)) + + static defaultProps = { +>defaultProps : Symbol(FieldFeedback2.defaultProps, Decl(reactDefaultPropsInferenceSuccess.tsx, 32, 86)) + + when: () => true +>when : Symbol(when, Decl(reactDefaultPropsInferenceSuccess.tsx, 33, 25)) + + }; + + render() { +>render : Symbol(FieldFeedback2.render, Decl(reactDefaultPropsInferenceSuccess.tsx, 35, 4)) + + this.props.when("now"); // OK, always defined +>this.props.when : Symbol(when, Decl(reactDefaultPropsInferenceSuccess.tsx, 28, 38)) +>this.props : Symbol(React.Component.props, Decl(react16.d.ts, 367, 32)) +>this : Symbol(FieldFeedback2, Decl(reactDefaultPropsInferenceSuccess.tsx, 30, 1)) +>props : Symbol(React.Component.props, Decl(react16.d.ts, 367, 32)) +>when : Symbol(when, Decl(reactDefaultPropsInferenceSuccess.tsx, 28, 38)) + + return

Hello
; +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114)) + } +} + +// OK +const Test3 = () => !!value} />; +>Test3 : Symbol(Test3, Decl(reactDefaultPropsInferenceSuccess.tsx, 44, 5)) +>FieldFeedback2 : Symbol(FieldFeedback2, Decl(reactDefaultPropsInferenceSuccess.tsx, 30, 1)) +>when : Symbol(when, Decl(reactDefaultPropsInferenceSuccess.tsx, 44, 35)) +>value : Symbol(value, Decl(reactDefaultPropsInferenceSuccess.tsx, 44, 42)) +>value : Symbol(value, Decl(reactDefaultPropsInferenceSuccess.tsx, 44, 42)) + +// Error: Void not assignable to boolean +const Test4 = () => console.log(value)} />; +>Test4 : Symbol(Test4, Decl(reactDefaultPropsInferenceSuccess.tsx, 47, 5)) +>FieldFeedback2 : Symbol(FieldFeedback2, Decl(reactDefaultPropsInferenceSuccess.tsx, 30, 1)) +>when : Symbol(when, Decl(reactDefaultPropsInferenceSuccess.tsx, 47, 35)) +>value : Symbol(value, Decl(reactDefaultPropsInferenceSuccess.tsx, 47, 42)) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>value : Symbol(value, Decl(reactDefaultPropsInferenceSuccess.tsx, 47, 42)) + +// OK +const Test5 = () => ; +>Test5 : Symbol(Test5, Decl(reactDefaultPropsInferenceSuccess.tsx, 50, 5)) +>FieldFeedback2 : Symbol(FieldFeedback2, Decl(reactDefaultPropsInferenceSuccess.tsx, 30, 1)) + diff --git a/tests/baselines/reference/reactDefaultPropsInferenceSuccess.types b/tests/baselines/reference/reactDefaultPropsInferenceSuccess.types new file mode 100644 index 0000000000000..91d918b092347 --- /dev/null +++ b/tests/baselines/reference/reactDefaultPropsInferenceSuccess.types @@ -0,0 +1,146 @@ +=== tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx === +/// + +import React from 'react'; +>React : typeof React + +interface BaseProps { + when?: (value: string) => boolean; +>when : ((value: string) => boolean) | undefined +>value : string +} + +interface Props extends BaseProps { +} + +class FieldFeedback

extends React.Component

{ +>FieldFeedback : FieldFeedback

+>React.Component : React.Component +>React : typeof React +>Component : typeof React.Component + + static defaultProps = { +>defaultProps : { when: () => boolean; } +>{ when: () => true } : { when: () => boolean; } + + when: () => true +>when : () => boolean +>() => true : () => boolean +>true : true + + }; + + render() { +>render : () => JSX.Element + + return

Hello
; +>
Hello
: JSX.Element +>div : any +>div : any + } +} + +// OK +const Test1 = () => !!value} />; +>Test1 : () => JSX.Element +>() => !!value} /> : () => JSX.Element +> !!value} /> : JSX.Element +>FieldFeedback : typeof FieldFeedback +>when : (value: string) => boolean +>value => !!value : (value: string) => boolean +>value : string +>!!value : boolean +>!value : boolean +>value : string + +// Error: Void not assignable to boolean +const Test2 = () => console.log(value)} />; +>Test2 : () => JSX.Element +>() => console.log(value)} /> : () => JSX.Element +> console.log(value)} /> : JSX.Element +>FieldFeedback : typeof FieldFeedback +>when : (value: string) => void +>value => console.log(value) : (value: string) => void +>value : string +>console.log(value) : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>value : string + + +interface MyPropsProps extends Props { + when: (value: string) => boolean; +>when : (value: string) => boolean +>value : string +} + +class FieldFeedback2

extends FieldFeedback

{ +>FieldFeedback2 : FieldFeedback2

+>FieldFeedback : FieldFeedback

+ + static defaultProps = { +>defaultProps : { when: () => boolean; } +>{ when: () => true } : { when: () => boolean; } + + when: () => true +>when : () => boolean +>() => true : () => boolean +>true : true + + }; + + render() { +>render : () => JSX.Element + + this.props.when("now"); // OK, always defined +>this.props.when("now") : boolean +>this.props.when : P["when"] +>this.props : Readonly<{ children?: React.ReactNode; }> & Readonly

+>this : this +>props : Readonly<{ children?: React.ReactNode; }> & Readonly

+>when : P["when"] +>"now" : "now" + + return

Hello
; +>
Hello
: JSX.Element +>div : any +>div : any + } +} + +// OK +const Test3 = () => !!value} />; +>Test3 : () => JSX.Element +>() => !!value} /> : () => JSX.Element +> !!value} /> : JSX.Element +>FieldFeedback2 : typeof FieldFeedback2 +>when : (value: string) => boolean +>value => !!value : (value: string) => boolean +>value : string +>!!value : boolean +>!value : boolean +>value : string + +// Error: Void not assignable to boolean +const Test4 = () => console.log(value)} />; +>Test4 : () => JSX.Element +>() => console.log(value)} /> : () => JSX.Element +> console.log(value)} /> : JSX.Element +>FieldFeedback2 : typeof FieldFeedback2 +>when : (value: string) => void +>value => console.log(value) : (value: string) => void +>value : string +>console.log(value) : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>value : string + +// OK +const Test5 = () => ; +>Test5 : () => JSX.Element +>() => : () => JSX.Element +> : JSX.Element +>FieldFeedback2 : typeof FieldFeedback2 + diff --git a/tests/cases/compiler/conditionalTypeContextualTypeSimplificationsSuceeds.ts b/tests/cases/compiler/conditionalTypeContextualTypeSimplificationsSuceeds.ts new file mode 100644 index 0000000000000..f585022cccfa7 --- /dev/null +++ b/tests/cases/compiler/conditionalTypeContextualTypeSimplificationsSuceeds.ts @@ -0,0 +1,16 @@ +// @strict: true +// repro from https://github.com/Microsoft/TypeScript/issues/26395 +interface Props { + when: (value: string) => boolean; +} + +function bad

( + attrs: string extends keyof P ? { [K in keyof P]: P[K] } : { [K in keyof P]: P[K] }) { } +function good1

( + attrs: string extends keyof P ? P : { [K in keyof P]: P[K] }) { } +function good2

( + attrs: { [K in keyof P]: P[K] }) { } + +bad({ when: value => false }); +good1({ when: value => false }); +good2({ when: value => false }); \ No newline at end of file diff --git a/tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx b/tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx new file mode 100644 index 0000000000000..9de13d119df47 --- /dev/null +++ b/tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx @@ -0,0 +1,54 @@ +// @jsx: react +// @strict: true +// @esModuleInterop: true +/// + +import React from 'react'; + +interface BaseProps { + when?: (value: string) => boolean; +} + +interface Props extends BaseProps { +} + +class FieldFeedback

extends React.Component

{ + static defaultProps = { + when: () => true + }; + + render() { + return

Hello
; + } +} + +// OK +const Test1 = () => !!value} />; + +// Error: Void not assignable to boolean +const Test2 = () => console.log(value)} />; + + +interface MyPropsProps extends Props { + when: (value: string) => boolean; +} + +class FieldFeedback2

extends FieldFeedback

{ + static defaultProps = { + when: () => true + }; + + render() { + this.props.when("now"); // OK, always defined + return

Hello
; + } +} + +// OK +const Test3 = () => !!value} />; + +// Error: Void not assignable to boolean +const Test4 = () => console.log(value)} />; + +// OK +const Test5 = () => ; diff --git a/tests/lib/react16.d.ts b/tests/lib/react16.d.ts new file mode 100644 index 0000000000000..4b91fb0c6fed9 --- /dev/null +++ b/tests/lib/react16.d.ts @@ -0,0 +1,2569 @@ +// Type definitions for React 16.4 +// Project: http://facebook.github.io/react/ +// Definitions by: Asana +// AssureSign +// Microsoft +// John Reilly +// Benoit Benezech +// Patricio Zavolinsky +// Digiguru +// Eric Anderson +// Albert Kurniawan +// Tanguy Krotoff +// Dovydas Navickas +// Stéphane Goetz +// Josh Rutherford +// Guilherme Hübner +// Ferdy Budhidharma +// Johann Rakotoharisoa +// Olivier Pascal +// Martin Hochel +// Frank Li +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.8 + +interface HTMLWebViewElement extends HTMLElement {} + +declare module "prop-types" { + // Type definitions for prop-types 15.5 + // Project: https://github.com/reactjs/prop-types + // Definitions by: DovydasNavickas + // Ferdy Budhidharma + // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + // TypeScript Version: 2.8 + + import { ReactNode, ReactElement } from 'react'; + + export const nominalTypeHack: unique symbol; + + export type IsOptional = undefined | null extends T ? true : undefined extends T ? true : null extends T ? true : false; + + export type RequiredKeys = { [K in keyof V]: V[K] extends Validator ? IsOptional extends true ? never : K : never }[keyof V]; + export type OptionalKeys = Exclude>; + export type InferPropsInner = { [K in keyof V]: InferType; }; + + export interface Validator { + (props: object, propName: string, componentName: string, location: string, propFullName: string): Error | null; + [nominalTypeHack]?: T; + } + + export interface Requireable extends Validator { + isRequired: Validator>; + } + + export type ValidationMap = { [K in keyof T]-?: Validator }; + + export type InferType = V extends Validator ? T : any; + export type InferProps = + & InferPropsInner>> + & Partial>>>; + + export const any: Requireable; + export const array: Requireable; + export const bool: Requireable; + export const func: Requireable<(...args: any[]) => any>; + export const number: Requireable; + export const object: Requireable; + export const string: Requireable; + export const node: Requireable; + export const element: Requireable>; + export const symbol: Requireable; + export function instanceOf(expectedClass: new (...args: any[]) => T): Requireable; + export function oneOf(types: T[]): Requireable; + export function oneOfType>(types: T[]): Requireable>>; + export function arrayOf(type: Validator): Requireable; + export function objectOf(type: Validator): Requireable<{ [K in keyof any]: T; }>; + export function shape

>(type: P): Requireable>; + export function exact

>(type: P): Requireable>>; + + /** + * Assert that the values match with the type specs. + * Error messages are memorized and will only be shown once. + * + * @param typeSpecs Map of name to a ReactPropType + * @param values Runtime values that need to be type-checked + * @param location e.g. "prop", "context", "child context" + * @param componentName Name of the component for error messages. + * @param getStack Returns the component stack. + */ + export function checkPropTypes(typeSpecs: any, values: any, location: string, componentName: string, getStack?: () => any): void; + +} + +declare module "react" { + + import * as PropTypes from 'prop-types'; + + type NativeAnimationEvent = AnimationEvent; + type NativeClipboardEvent = ClipboardEvent; + type NativeCompositionEvent = CompositionEvent; + type NativeDragEvent = DragEvent; + type NativeFocusEvent = FocusEvent; + type NativeKeyboardEvent = KeyboardEvent; + type NativeMouseEvent = MouseEvent; + type NativeTouchEvent = TouchEvent; + type NativePointerEvent = PointerEvent; + type NativeTransitionEvent = TransitionEvent; + type NativeUIEvent = UIEvent; + type NativeWheelEvent = WheelEvent; + + // tslint:disable-next-line:export-just-namespace + export = React; + + namespace React { + // + // React Elements + // ---------------------------------------------------------------------- + + type ReactType

= string | ComponentType

; + type ComponentType

= ComponentClass

| StatelessComponent

; + + type Key = string | number; + + interface RefObject { + readonly current: T | null; + } + + type Ref = string | { bivarianceHack(instance: T | null): any }["bivarianceHack"] | RefObject; + + type ComponentState = any; + + interface Attributes { + key?: Key; + } + interface ClassAttributes extends Attributes { + ref?: Ref; + } + + interface ReactElement

{ + type: string | ComponentClass

| SFC

; + props: P; + key: Key | null; + } + + interface SFCElement

extends ReactElement

{ + type: SFC

; + } + + type CElement> = ComponentElement; + interface ComponentElement> extends ReactElement

{ + type: ComponentClass

; + ref?: Ref; + } + + type ClassicElement

= CElement>; + + // string fallback for custom web-components + interface DOMElement

| SVGAttributes, T extends Element> extends ReactElement

{ + type: string; + ref: Ref; + } + + // ReactHTML for ReactHTMLElement + // tslint:disable-next-line:no-empty-interface + interface ReactHTMLElement extends DetailedReactHTMLElement, T> { } + + interface DetailedReactHTMLElement

, T extends HTMLElement> extends DOMElement { + type: keyof ReactHTML; + } + + // ReactSVG for ReactSVGElement + interface ReactSVGElement extends DOMElement, SVGElement> { + type: keyof ReactSVG; + } + + interface ReactPortal extends ReactElement { + key: Key | null; + children: ReactNode; + } + + // + // Factories + // ---------------------------------------------------------------------- + + type Factory

= (props?: Attributes & P, ...children: ReactNode[]) => ReactElement

; + + type SFCFactory

= (props?: Attributes & P, ...children: ReactNode[]) => SFCElement

; + + type ComponentFactory> = + (props?: ClassAttributes & P, ...children: ReactNode[]) => CElement; + + type CFactory> = ComponentFactory; + type ClassicFactory

= CFactory>; + + type DOMFactory

, T extends Element> = + (props?: ClassAttributes & P | null, ...children: ReactNode[]) => DOMElement; + + // tslint:disable-next-line:no-empty-interface + interface HTMLFactory extends DetailedHTMLFactory, T> { } + + interface DetailedHTMLFactory

, T extends HTMLElement> extends DOMFactory { + (props?: ClassAttributes & P | null, ...children: ReactNode[]): DetailedReactHTMLElement; + } + + interface SVGFactory extends DOMFactory, SVGElement> { + (props?: ClassAttributes & SVGAttributes | null, ...children: ReactNode[]): ReactSVGElement; + } + + // + // React Nodes + // http://facebook.github.io/react/docs/glossary.html + // ---------------------------------------------------------------------- + + type ReactText = string | number; + type ReactChild = ReactElement | ReactText; + + interface ReactNodeArray extends Array { } + type ReactFragment = {} | ReactNodeArray; + type ReactNode = ReactChild | ReactFragment | ReactPortal | string | number | boolean | null | undefined; + + // + // Top Level API + // ---------------------------------------------------------------------- + + // DOM Elements + function createFactory( + type: keyof ReactHTML): HTMLFactory; + function createFactory( + type: keyof ReactSVG): SVGFactory; + function createFactory

, T extends Element>( + type: string): DOMFactory; + + // Custom components + function createFactory

(type: SFC

): SFCFactory

; + function createFactory

( + type: ClassType, ClassicComponentClass

>): CFactory>; + function createFactory, C extends ComponentClass

>( + type: ClassType): CFactory; + function createFactory

(type: ComponentClass

): Factory

; + + // DOM Elements + // TODO: generalize this to everything in `keyof ReactHTML`, not just "input" + function createElement( + type: "input", + props?: InputHTMLAttributes & ClassAttributes | null, + ...children: ReactNode[]): DetailedReactHTMLElement, HTMLInputElement>; + function createElement

, T extends HTMLElement>( + type: keyof ReactHTML, + props?: ClassAttributes & P | null, + ...children: ReactNode[]): DetailedReactHTMLElement; + function createElement

, T extends SVGElement>( + type: keyof ReactSVG, + props?: ClassAttributes & P | null, + ...children: ReactNode[]): ReactSVGElement; + function createElement

, T extends Element>( + type: string, + props?: ClassAttributes & P | null, + ...children: ReactNode[]): DOMElement; + + // Custom components + function createElement

( + type: SFC

, + props?: Attributes & P | null, + ...children: ReactNode[]): SFCElement

; + function createElement

( + type: ClassType, ClassicComponentClass

>, + props?: ClassAttributes> & P | null, + ...children: ReactNode[]): CElement>; + function createElement, C extends ComponentClass

>( + type: ClassType, + props?: ClassAttributes & P | null, + ...children: ReactNode[]): CElement; + function createElement

( + type: SFC

| ComponentClass

| string, + props?: Attributes & P | null, + ...children: ReactNode[]): ReactElement

; + + // DOM Elements + // ReactHTMLElement + function cloneElement

, T extends HTMLElement>( + element: DetailedReactHTMLElement, + props?: P, + ...children: ReactNode[]): DetailedReactHTMLElement; + // ReactHTMLElement, less specific + function cloneElement

, T extends HTMLElement>( + element: ReactHTMLElement, + props?: P, + ...children: ReactNode[]): ReactHTMLElement; + // SVGElement + function cloneElement

, T extends SVGElement>( + element: ReactSVGElement, + props?: P, + ...children: ReactNode[]): ReactSVGElement; + // DOM Element (has to be the last, because type checking stops at first overload that fits) + function cloneElement

, T extends Element>( + element: DOMElement, + props?: DOMAttributes & P, + ...children: ReactNode[]): DOMElement; + + // Custom components + function cloneElement

( + element: SFCElement

, + props?: Partial

& Attributes, + ...children: ReactNode[]): SFCElement

; + function cloneElement>( + element: CElement, + props?: Partial

& ClassAttributes, + ...children: ReactNode[]): CElement; + function cloneElement

( + element: ReactElement

, + props?: Partial

& Attributes, + ...children: ReactNode[]): ReactElement

; + + // Context via RenderProps + interface ProviderProps { + value: T; + children?: ReactNode; + } + + interface ConsumerProps { + children: (value: T) => ReactNode; + unstable_observedBits?: number; + } + + type Provider = ComponentType>; + type Consumer = ComponentType>; + interface Context { + Provider: Provider; + Consumer: Consumer; + } + function createContext( + defaultValue: T, + calculateChangedBits?: (prev: T, next: T) => number + ): Context; + + function isValidElement

(object: {} | null | undefined): object is ReactElement

; + + const Children: ReactChildren; + const Fragment: ComponentType; + const StrictMode: ComponentType; + const version: string; + + // + // Component API + // ---------------------------------------------------------------------- + + type ReactInstance = Component | Element; + + // Base component for plain JS classes + // tslint:disable-next-line:no-empty-interface + interface Component

extends ComponentLifecycle { } + class Component { + constructor(props: Readonly

); + /** + * @deprecated + * https://reactjs.org/docs/legacy-context.html + */ + constructor(props: P, context?: any); + + // We MUST keep setState() as a unified signature because it allows proper checking of the method return type. + // See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257 + // Also, the ` | S` allows intellisense to not be dumbisense + setState( + state: ((prevState: Readonly, props: Readonly

) => (Pick | S | null)) | (Pick | S | null), + callback?: () => void + ): void; + + forceUpdate(callBack?: () => void): void; + render(): ReactNode; + + // React.Props is now deprecated, which means that the `children` + // property is not available on `P` by default, even though you can + // always pass children as variadic arguments to `createElement`. + // In the future, if we can define its call signature conditionally + // on the existence of `children` in `P`, then we should remove this. + readonly props: Readonly<{ children?: ReactNode }> & Readonly

; + state: Readonly; + /** + * @deprecated + * https://reactjs.org/docs/legacy-context.html + */ + context: any; + /** + * @deprecated + * https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs + */ + refs: { + [key: string]: ReactInstance + }; + } + + class PureComponent

extends Component { } + + interface ClassicComponent

extends Component { + replaceState(nextState: S, callback?: () => void): void; + isMounted(): boolean; + getInitialState?(): S; + } + + interface ChildContextProvider { + getChildContext(): CC; + } + + // + // Class Interfaces + // ---------------------------------------------------------------------- + + type SFC

= StatelessComponent

; + interface StatelessComponent

{ + (props: P & { children?: ReactNode }, context?: any): ReactElement | null; + propTypes?: ValidationMap

; + contextTypes?: ValidationMap; + defaultProps?: Partial

; + displayName?: string; + } + + interface RefForwardingComponent { + (props: P & { children?: ReactNode }, ref?: Ref): ReactElement | null; + propTypes?: ValidationMap

; + contextTypes?: ValidationMap; + defaultProps?: Partial

; + displayName?: string; + } + + interface ComponentClass

extends StaticLifecycle { + new(props: P, context?: any): Component; + propTypes?: ValidationMap

; + contextTypes?: ValidationMap; + childContextTypes?: ValidationMap; + defaultProps?: Partial

; + displayName?: string; + } + + interface ClassicComponentClass

extends ComponentClass

{ + new(props: P, context?: any): ClassicComponent; + getDefaultProps?(): P; + } + + /** + * We use an intersection type to infer multiple type parameters from + * a single argument, which is useful for many top-level API defs. + * See https://github.com/Microsoft/TypeScript/issues/7234 for more info. + */ + type ClassType, C extends ComponentClass

> = + C & + (new (props: P, context?: any) => T) & + (new (props: P, context?: any) => { props: P }); + + // + // Component Specs and Lifecycle + // ---------------------------------------------------------------------- + + // This should actually be something like `Lifecycle | DeprecatedLifecycle`, + // as React will _not_ call the deprecated lifecycle methods if any of the new lifecycle + // methods are present. + interface ComponentLifecycle extends NewLifecycle, DeprecatedLifecycle { + /** + * Called immediately after a component is mounted. Setting state here will trigger re-rendering. + */ + componentDidMount?(): void; + /** + * Called to determine whether the change in props and state should trigger a re-render. + * + * `Component` always returns true. + * `PureComponent` implements a shallow comparison on props and state and returns true if any + * props or states have changed. + * + * If false is returned, `Component#render`, `componentWillUpdate` + * and `componentDidUpdate` will not be called. + */ + shouldComponentUpdate?(nextProps: Readonly

, nextState: Readonly, nextContext: any): boolean; + /** + * Called immediately before a component is destroyed. Perform any necessary cleanup in this method, such as + * cancelled network requests, or cleaning up any DOM elements created in `componentDidMount`. + */ + componentWillUnmount?(): void; + /** + * Catches exceptions generated in descendant components. Unhandled exceptions will cause + * the entire component tree to unmount. + */ + componentDidCatch?(error: Error, errorInfo: ErrorInfo): void; + } + + // Unfortunately, we have no way of declaring that the component constructor must implement this + interface StaticLifecycle { + getDerivedStateFromProps?: GetDerivedStateFromProps; + } + + type GetDerivedStateFromProps = + /** + * Returns an update to a component's state based on its new props and old state. + * + * Note: its presence prevents any of the deprecated lifecycle methods from being invoked + */ + (nextProps: Readonly

, prevState: S) => Partial | null; + + // This should be "infer SS" but can't use it yet + interface NewLifecycle { + /** + * Runs before React applies the result of `render` to the document, and + * returns an object to be given to componentDidUpdate. Useful for saving + * things such as scroll position before `render` causes changes to it. + * + * Note: the presence of getSnapshotBeforeUpdate prevents any of the deprecated + * lifecycle events from running. + */ + getSnapshotBeforeUpdate?(prevProps: Readonly

, prevState: Readonly): SS | null; + /** + * Called immediately after updating occurs. Not called for the initial render. + * + * The snapshot is only present if getSnapshotBeforeUpdate is present and returns non-null. + */ + componentDidUpdate?(prevProps: Readonly

, prevState: Readonly, snapshot?: SS): void; + } + + interface DeprecatedLifecycle { + /** + * Called immediately before mounting occurs, and before `Component#render`. + * Avoid introducing any side-effects or subscriptions in this method. + * + * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps + * prevents this from being invoked. + * + * @deprecated 16.3, use componentDidMount or the constructor instead; will stop working in React 17 + * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#initializing-state + * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path + */ + componentWillMount?(): void; + /** + * Called immediately before mounting occurs, and before `Component#render`. + * Avoid introducing any side-effects or subscriptions in this method. + * + * This method will not stop working in React 17. + * + * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps + * prevents this from being invoked. + * + * @deprecated 16.3, use componentDidMount or the constructor instead + * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#initializing-state + * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path + */ + UNSAFE_componentWillMount?(): void; + /** + * Called when the component may be receiving new props. + * React may call this even if props have not changed, so be sure to compare new and existing + * props if you only want to handle changes. + * + * Calling `Component#setState` generally does not trigger this method. + * + * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps + * prevents this from being invoked. + * + * @deprecated 16.3, use static getDerivedStateFromProps instead; will stop working in React 17 + * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#updating-state-based-on-props + * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path + */ + componentWillReceiveProps?(nextProps: Readonly

, nextContext: any): void; + /** + * Called when the component may be receiving new props. + * React may call this even if props have not changed, so be sure to compare new and existing + * props if you only want to handle changes. + * + * Calling `Component#setState` generally does not trigger this method. + * + * This method will not stop working in React 17. + * + * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps + * prevents this from being invoked. + * + * @deprecated 16.3, use static getDerivedStateFromProps instead + * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#updating-state-based-on-props + * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path + */ + UNSAFE_componentWillReceiveProps?(nextProps: Readonly

, nextContext: any): void; + /** + * Called immediately before rendering when new props or state is received. Not called for the initial render. + * + * Note: You cannot call `Component#setState` here. + * + * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps + * prevents this from being invoked. + * + * @deprecated 16.3, use getSnapshotBeforeUpdate instead; will stop working in React 17 + * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#reading-dom-properties-before-an-update + * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path + */ + componentWillUpdate?(nextProps: Readonly

, nextState: Readonly, nextContext: any): void; + /** + * Called immediately before rendering when new props or state is received. Not called for the initial render. + * + * Note: You cannot call `Component#setState` here. + * + * This method will not stop working in React 17. + * + * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps + * prevents this from being invoked. + * + * @deprecated 16.3, use getSnapshotBeforeUpdate instead + * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#reading-dom-properties-before-an-update + * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path + */ + UNSAFE_componentWillUpdate?(nextProps: Readonly

, nextState: Readonly, nextContext: any): void; + } + + interface Mixin extends ComponentLifecycle { + mixins?: Array>; + statics?: { + [key: string]: any; + }; + + displayName?: string; + propTypes?: ValidationMap; + contextTypes?: ValidationMap; + childContextTypes?: ValidationMap; + + getDefaultProps?(): P; + getInitialState?(): S; + } + + interface ComponentSpec extends Mixin { + render(): ReactNode; + + [propertyName: string]: any; + } + + function createRef(): RefObject; + + function forwardRef(Component: RefForwardingComponent): ComponentType

>; + + // + // Event System + // ---------------------------------------------------------------------- + + interface SyntheticEvent { + bubbles: boolean; + /** + * A reference to the element on which the event listener is registered. + */ + currentTarget: EventTarget & T; + cancelable: boolean; + defaultPrevented: boolean; + eventPhase: number; + isTrusted: boolean; + nativeEvent: Event; + preventDefault(): void; + isDefaultPrevented(): boolean; + stopPropagation(): void; + isPropagationStopped(): boolean; + persist(): void; + // If you thought this should be `EventTarget & T`, see https://github.com/DefinitelyTyped/DefinitelyTyped/pull/12239 + /** + * A reference to the element from which the event was originally dispatched. + * This might be a child element to the element on which the event listener is registered. + * + * @see currentTarget + */ + target: EventTarget; + timeStamp: number; + type: string; + } + + interface ClipboardEvent extends SyntheticEvent { + clipboardData: DataTransfer; + nativeEvent: NativeClipboardEvent; + } + + interface CompositionEvent extends SyntheticEvent { + data: string; + nativeEvent: NativeCompositionEvent; + } + + interface DragEvent extends MouseEvent { + dataTransfer: DataTransfer; + nativeEvent: NativeDragEvent; + } + + interface PointerEvent extends MouseEvent { + pointerId: number; + pressure: number; + tiltX: number; + tiltY: number; + width: number; + height: number; + pointerType: 'mouse' | 'pen' | 'touch'; + isPrimary: boolean; + nativeEvent: NativePointerEvent; + } + + interface FocusEvent extends SyntheticEvent { + nativeEvent: NativeFocusEvent; + relatedTarget: EventTarget; + target: EventTarget & T; + } + + // tslint:disable-next-line:no-empty-interface + interface FormEvent extends SyntheticEvent { + } + + interface InvalidEvent extends SyntheticEvent { + target: EventTarget & T; + } + + interface ChangeEvent extends SyntheticEvent { + target: EventTarget & T; + } + + interface KeyboardEvent extends SyntheticEvent { + altKey: boolean; + charCode: number; + ctrlKey: boolean; + /** + * See [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#keys-modifier). for a list of valid (case-sensitive) arguments to this method. + */ + getModifierState(key: string): boolean; + /** + * See the [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#named-key-attribute-values). for possible values + */ + key: string; + keyCode: number; + locale: string; + location: number; + metaKey: boolean; + nativeEvent: NativeKeyboardEvent; + repeat: boolean; + shiftKey: boolean; + which: number; + } + + interface MouseEvent extends SyntheticEvent { + altKey: boolean; + button: number; + buttons: number; + clientX: number; + clientY: number; + ctrlKey: boolean; + /** + * See [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#keys-modifier). for a list of valid (case-sensitive) arguments to this method. + */ + getModifierState(key: string): boolean; + metaKey: boolean; + nativeEvent: NativeMouseEvent; + pageX: number; + pageY: number; + relatedTarget: EventTarget; + screenX: number; + screenY: number; + shiftKey: boolean; + } + + interface TouchEvent extends SyntheticEvent { + altKey: boolean; + changedTouches: TouchList; + ctrlKey: boolean; + /** + * See [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#keys-modifier). for a list of valid (case-sensitive) arguments to this method. + */ + getModifierState(key: string): boolean; + metaKey: boolean; + nativeEvent: NativeTouchEvent; + shiftKey: boolean; + targetTouches: TouchList; + touches: TouchList; + } + + interface UIEvent extends SyntheticEvent { + detail: number; + nativeEvent: NativeUIEvent; + view: AbstractView; + } + + interface WheelEvent extends MouseEvent { + deltaMode: number; + deltaX: number; + deltaY: number; + deltaZ: number; + nativeEvent: NativeWheelEvent; + } + + interface AnimationEvent extends SyntheticEvent { + animationName: string; + elapsedTime: number; + nativeEvent: NativeAnimationEvent; + pseudoElement: string; + } + + interface TransitionEvent extends SyntheticEvent { + elapsedTime: number; + nativeEvent: NativeTransitionEvent; + propertyName: string; + pseudoElement: string; + } + + // + // Event Handler Types + // ---------------------------------------------------------------------- + + type EventHandler> = { bivarianceHack(event: E): void }["bivarianceHack"]; + + type ReactEventHandler = EventHandler>; + + type ClipboardEventHandler = EventHandler>; + type CompositionEventHandler = EventHandler>; + type DragEventHandler = EventHandler>; + type FocusEventHandler = EventHandler>; + type FormEventHandler = EventHandler>; + type ChangeEventHandler = EventHandler>; + type KeyboardEventHandler = EventHandler>; + type MouseEventHandler = EventHandler>; + type TouchEventHandler = EventHandler>; + type PointerEventHandler = EventHandler>; + type UIEventHandler = EventHandler>; + type WheelEventHandler = EventHandler>; + type AnimationEventHandler = EventHandler>; + type TransitionEventHandler = EventHandler>; + + // + // Props / DOM Attributes + // ---------------------------------------------------------------------- + + /** + * @deprecated. This was used to allow clients to pass `ref` and `key` + * to `createElement`, which is no longer necessary due to intersection + * types. If you need to declare a props object before passing it to + * `createElement` or a factory, use `ClassAttributes`: + * + * ```ts + * var b: Button | null; + * var props: ButtonProps & ClassAttributes