Fixing react defaultize+generic default props interaction (#27088)

* Add repro for fixed issue

* Fix JSX propagating flags and contextual types

* Accept slightly changed baselines

* Add modern react.d.ts and regression test
This commit is contained in:
Wesley Wigham 2018-09-14 14:18:47 -07:00 committed by GitHub
parent bce34ada8f
commit 4eb59a2d77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 3261 additions and 16 deletions

View File

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

View File

@ -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 = <GenericComponent initialValues={{ x: "y" }} nextValues={a => ({ x: a.x })} />; // No Error
let d = <GenericComponent initialValues={{ x: "y" }} nextValues={a => 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<GenericComponent<{ initialValues: { x: string; }; nextValues: {}; }, { x: string; }>> & { initialValues: { x: string; }; nextValues: {}; } & BaseProps<{ x: string; }> & { children?: ReactNode; }'
!!! 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<GenericComponent<{ initialValues: { x: string; }; nextValues: (a: { x: string; }) => string; }, { x: string; }>> & { initialValues: { x: string; }; nextValues: (a: { x: string; }) => string; } & BaseProps<{ x: string; }> & { children?: ReactNode; }'

View File

@ -0,0 +1,25 @@
//// [conditionalTypeContextualTypeSimplificationsSuceeds.ts]
// repro from https://github.com/Microsoft/TypeScript/issues/26395
interface Props {
when: (value: string) => boolean;
}
function bad<P extends Props>(
attrs: string extends keyof P ? { [K in keyof P]: P[K] } : { [K in keyof P]: P[K] }) { }
function good1<P extends Props>(
attrs: string extends keyof P ? P : { [K in keyof P]: P[K] }) { }
function good2<P extends Props>(
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; } });

View File

@ -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<P extends Props>(
>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<P extends Props>(
>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<P extends Props>(
>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))

View File

@ -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<P extends Props>(
>bad : <P extends Props>(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<P extends Props>(
>good1 : <P extends Props>(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<P extends Props>(
>good2 : <P extends Props>(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 : <P extends Props>(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 : <P extends Props>(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 : <P extends Props>(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

View File

@ -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 = <ElemLit prop="x" children={p => "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 = <ElemLit prop="x">{p => "y"}</ElemLit>

View File

@ -117,9 +117,9 @@ const arg = <ElemLit prop="x" children={p => "y"} />
><ElemLit prop="x" children={p => "y"} /> : JSX.Element
>ElemLit : <T extends string>(p: LitProps<T>) => 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 = <ElemLit prop="x">{p => "y"}</ElemLit>

View File

@ -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) ====
/// <reference path="/.lib/react16.d.ts" />
import React from 'react';
interface BaseProps {
when?: (value: string) => boolean;
}
interface Props extends BaseProps {
}
class FieldFeedback<P extends Props = BaseProps> extends React.Component<P> {
static defaultProps = {
when: () => true
};
render() {
return <div>Hello</div>;
}
}
// OK
const Test1 = () => <FieldFeedback when={value => !!value} />;
// Error: Void not assignable to boolean
const Test2 = () => <FieldFeedback when={value => 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<FieldFeedback<Props>> & Pick<Readonly<{ children?: ReactNode; }> & Readonly<Props>, "children"> & Partial<Pick<Readonly<{ children?: ReactNode; }> & Readonly<Props>, "when">> & Partial<Pick<{ when: () => boolean; }, never>>'
interface MyPropsProps extends Props {
when: (value: string) => boolean;
}
class FieldFeedback2<P extends MyPropsProps = MyPropsProps> extends FieldFeedback<P> {
static defaultProps = {
when: () => true
};
render() {
this.props.when("now"); // OK, always defined
return <div>Hello</div>;
}
}
// OK
const Test3 = () => <FieldFeedback2 when={value => !!value} />;
// Error: Void not assignable to boolean
const Test4 = () => <FieldFeedback2 when={value => 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<FieldFeedback2<MyPropsProps>> & Pick<Readonly<{ children?: ReactNode; }> & Readonly<MyPropsProps>, "children"> & Partial<Pick<Readonly<{ children?: ReactNode; }> & Readonly<MyPropsProps>, "when">> & Partial<Pick<{ when: () => boolean; }, never>>'
// OK
const Test5 = () => <FieldFeedback2 />;

View File

@ -0,0 +1,112 @@
//// [reactDefaultPropsInferenceSuccess.tsx]
/// <reference path="/.lib/react16.d.ts" />
import React from 'react';
interface BaseProps {
when?: (value: string) => boolean;
}
interface Props extends BaseProps {
}
class FieldFeedback<P extends Props = BaseProps> extends React.Component<P> {
static defaultProps = {
when: () => true
};
render() {
return <div>Hello</div>;
}
}
// OK
const Test1 = () => <FieldFeedback when={value => !!value} />;
// Error: Void not assignable to boolean
const Test2 = () => <FieldFeedback when={value => console.log(value)} />;
interface MyPropsProps extends Props {
when: (value: string) => boolean;
}
class FieldFeedback2<P extends MyPropsProps = MyPropsProps> extends FieldFeedback<P> {
static defaultProps = {
when: () => true
};
render() {
this.props.when("now"); // OK, always defined
return <div>Hello</div>;
}
}
// OK
const Test3 = () => <FieldFeedback2 when={value => !!value} />;
// Error: Void not assignable to boolean
const Test4 = () => <FieldFeedback2 when={value => console.log(value)} />;
// OK
const Test5 = () => <FieldFeedback2 />;
//// [reactDefaultPropsInferenceSuccess.js]
"use strict";
/// <reference path="react16.d.ts" />
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); };

View File

@ -0,0 +1,131 @@
=== tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx ===
/// <reference path="react16.d.ts" />
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<P extends Props = BaseProps> extends React.Component<P> {
>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 <div>Hello</div>;
>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 = () => <FieldFeedback when={value => !!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 = () => <FieldFeedback when={value => 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<P extends MyPropsProps = MyPropsProps> extends FieldFeedback<P> {
>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 <div>Hello</div>;
>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 = () => <FieldFeedback2 when={value => !!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 = () => <FieldFeedback2 when={value => 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 = () => <FieldFeedback2 />;
>Test5 : Symbol(Test5, Decl(reactDefaultPropsInferenceSuccess.tsx, 50, 5))
>FieldFeedback2 : Symbol(FieldFeedback2, Decl(reactDefaultPropsInferenceSuccess.tsx, 30, 1))

View File

@ -0,0 +1,146 @@
=== tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx ===
/// <reference path="react16.d.ts" />
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<P extends Props = BaseProps> extends React.Component<P> {
>FieldFeedback : FieldFeedback<P>
>React.Component : React.Component<P, {}, any>
>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 <div>Hello</div>;
><div>Hello</div> : JSX.Element
>div : any
>div : any
}
}
// OK
const Test1 = () => <FieldFeedback when={value => !!value} />;
>Test1 : () => JSX.Element
>() => <FieldFeedback when={value => !!value} /> : () => JSX.Element
><FieldFeedback when={value => !!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 = () => <FieldFeedback when={value => console.log(value)} />;
>Test2 : () => JSX.Element
>() => <FieldFeedback when={value => console.log(value)} /> : () => JSX.Element
><FieldFeedback when={value => 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<P extends MyPropsProps = MyPropsProps> extends FieldFeedback<P> {
>FieldFeedback2 : FieldFeedback2<P>
>FieldFeedback : FieldFeedback<P>
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<P>
>this : this
>props : Readonly<{ children?: React.ReactNode; }> & Readonly<P>
>when : P["when"]
>"now" : "now"
return <div>Hello</div>;
><div>Hello</div> : JSX.Element
>div : any
>div : any
}
}
// OK
const Test3 = () => <FieldFeedback2 when={value => !!value} />;
>Test3 : () => JSX.Element
>() => <FieldFeedback2 when={value => !!value} /> : () => JSX.Element
><FieldFeedback2 when={value => !!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 = () => <FieldFeedback2 when={value => console.log(value)} />;
>Test4 : () => JSX.Element
>() => <FieldFeedback2 when={value => console.log(value)} /> : () => JSX.Element
><FieldFeedback2 when={value => 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 = () => <FieldFeedback2 />;
>Test5 : () => JSX.Element
>() => <FieldFeedback2 /> : () => JSX.Element
><FieldFeedback2 /> : JSX.Element
>FieldFeedback2 : typeof FieldFeedback2

View File

@ -0,0 +1,16 @@
// @strict: true
// repro from https://github.com/Microsoft/TypeScript/issues/26395
interface Props {
when: (value: string) => boolean;
}
function bad<P extends Props>(
attrs: string extends keyof P ? { [K in keyof P]: P[K] } : { [K in keyof P]: P[K] }) { }
function good1<P extends Props>(
attrs: string extends keyof P ? P : { [K in keyof P]: P[K] }) { }
function good2<P extends Props>(
attrs: { [K in keyof P]: P[K] }) { }
bad({ when: value => false });
good1({ when: value => false });
good2({ when: value => false });

View File

@ -0,0 +1,54 @@
// @jsx: react
// @strict: true
// @esModuleInterop: true
/// <reference path="/.lib/react16.d.ts" />
import React from 'react';
interface BaseProps {
when?: (value: string) => boolean;
}
interface Props extends BaseProps {
}
class FieldFeedback<P extends Props = BaseProps> extends React.Component<P> {
static defaultProps = {
when: () => true
};
render() {
return <div>Hello</div>;
}
}
// OK
const Test1 = () => <FieldFeedback when={value => !!value} />;
// Error: Void not assignable to boolean
const Test2 = () => <FieldFeedback when={value => console.log(value)} />;
interface MyPropsProps extends Props {
when: (value: string) => boolean;
}
class FieldFeedback2<P extends MyPropsProps = MyPropsProps> extends FieldFeedback<P> {
static defaultProps = {
when: () => true
};
render() {
this.props.when("now"); // OK, always defined
return <div>Hello</div>;
}
}
// OK
const Test3 = () => <FieldFeedback2 when={value => !!value} />;
// Error: Void not assignable to boolean
const Test4 = () => <FieldFeedback2 when={value => console.log(value)} />;
// OK
const Test5 = () => <FieldFeedback2 />;

2569
tests/lib/react16.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff