Skip to content

Commit b7fc092

Browse files
authored
Fix non-selfclosing JSX tag contextual types (#27251)
1 parent 03af107 commit b7fc092

8 files changed

+272
-79
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16827,6 +16827,12 @@ namespace ts {
1682716827
}
1682816828

1682916829
function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement) {
16830+
if (isJsxOpeningElement(node) && node.parent.contextualType) {
16831+
// Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit
16832+
// _However_ to hit them from the _attributes_ we must look for them here; otherwise we'll used the declared type
16833+
// (as below) instead!
16834+
return node.parent.contextualType;
16835+
}
1683016836
if (isJsxIntrinsicIdentifier(node.tagName)) {
1683116837
return getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node);
1683216838
}

tests/baselines/reference/jsxChildrenGenericContextualTypes.errors.txt

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx(20,46): error TS2322: Type '"y"' is not assignable to type '"x"'.
2-
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">'.
3-
Type '{ children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'LitProps<"x" | "y">'.
2+
tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx(21,19): error TS2322: Type '{ children: (p: LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'IntrinsicAttributes & LitProps<"x" | "y">'.
3+
Type '{ children: (p: LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'LitProps<"x" | "y">'.
44
Types of property 'children' are incompatible.
5-
Type '(p: IntrinsicAttributes & LitProps<"x">) => "y"' is not assignable to type '(x: LitProps<"x" | "y">) => "x" | "y"'.
5+
Type '(p: LitProps<"x">) => "y"' is not assignable to type '(x: LitProps<"x" | "y">) => "x" | "y"'.
66
Types of parameters 'p' and 'x' are incompatible.
7-
Type 'LitProps<"x" | "y">' is not assignable to type 'IntrinsicAttributes & LitProps<"x">'.
8-
Type 'LitProps<"x" | "y">' is not assignable to type 'LitProps<"x">'.
9-
Types of property 'prop' are incompatible.
10-
Type '"x" | "y"' is not assignable to type '"x"'.
11-
Type '"y"' is not assignable to type '"x"'.
7+
Type 'LitProps<"x" | "y">' is not assignable to type 'LitProps<"x">'.
8+
Types of property 'prop' are incompatible.
9+
Type '"x" | "y"' is not assignable to type '"x"'.
10+
Type '"y"' is not assignable to type '"x"'.
1211
tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx(22,21): error TS2322: Type '{ children: () => number; prop: "x"; }' is not assignable to type 'IntrinsicAttributes & LitProps<"x">'.
1312
Type '{ children: () => number; prop: "x"; }' is not assignable to type 'LitProps<"x">'.
1413
Types of property 'children' are incompatible.
@@ -42,16 +41,15 @@ tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx(22,21): error TS2322:
4241
!!! related TS6502 tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx:13:44: The expected type comes from the return type of this signature.
4342
const argchild = <ElemLit prop="x">{p => "y"}</ElemLit>
4443
~~~~~~~
45-
!!! error TS2322: Type '{ children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'IntrinsicAttributes & LitProps<"x" | "y">'.
46-
!!! error TS2322: Type '{ children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'LitProps<"x" | "y">'.
44+
!!! error TS2322: Type '{ children: (p: LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'IntrinsicAttributes & LitProps<"x" | "y">'.
45+
!!! error TS2322: Type '{ children: (p: LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'LitProps<"x" | "y">'.
4746
!!! error TS2322: Types of property 'children' are incompatible.
48-
!!! error TS2322: Type '(p: IntrinsicAttributes & LitProps<"x">) => "y"' is not assignable to type '(x: LitProps<"x" | "y">) => "x" | "y"'.
47+
!!! error TS2322: Type '(p: LitProps<"x">) => "y"' is not assignable to type '(x: LitProps<"x" | "y">) => "x" | "y"'.
4948
!!! error TS2322: Types of parameters 'p' and 'x' are incompatible.
50-
!!! error TS2322: Type 'LitProps<"x" | "y">' is not assignable to type 'IntrinsicAttributes & LitProps<"x">'.
51-
!!! error TS2322: Type 'LitProps<"x" | "y">' is not assignable to type 'LitProps<"x">'.
52-
!!! error TS2322: Types of property 'prop' are incompatible.
53-
!!! error TS2322: Type '"x" | "y"' is not assignable to type '"x"'.
54-
!!! error TS2322: Type '"y"' is not assignable to type '"x"'.
49+
!!! error TS2322: Type 'LitProps<"x" | "y">' is not assignable to type 'LitProps<"x">'.
50+
!!! error TS2322: Types of property 'prop' are incompatible.
51+
!!! error TS2322: Type '"x" | "y"' is not assignable to type '"x"'.
52+
!!! error TS2322: Type '"y"' is not assignable to type '"x"'.
5553
const mismatched = <ElemLit prop="x">{() => 12}</ElemLit>
5654
~~~~~~~
5755
!!! error TS2322: Type '{ children: () => number; prop: "x"; }' is not assignable to type 'IntrinsicAttributes & LitProps<"x">'.

tests/baselines/reference/jsxChildrenGenericContextualTypes.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ const argchild = <ElemLit prop="x">{p => "y"}</ElemLit>
127127
><ElemLit prop="x">{p => "y"}</ElemLit> : JSX.Element
128128
>ElemLit : <T extends string>(p: LitProps<T>) => JSX.Element
129129
>prop : "x"
130-
>p => "y" : (p: JSX.IntrinsicAttributes & LitProps<"x">) => "y"
131-
>p : JSX.IntrinsicAttributes & LitProps<"x">
130+
>p => "y" : (p: LitProps<"x">) => "y"
131+
>p : LitProps<"x">
132132
>"y" : "y"
133133
>ElemLit : <T extends string>(p: LitProps<T>) => JSX.Element
134134

tests/baselines/reference/reactDefaultPropsInferenceSuccess.errors.txt

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
1-
tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx(26,36): error TS2322: Type '(value: string) => void' is not assignable to type '(value: string) => boolean'.
2-
Type 'void' is not assignable to type 'boolean'.
3-
tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx(48,37): error TS2322: Type '(value: string) => void' is not assignable to type '(value: string) => boolean'.
1+
tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx(27,36): error TS2322: Type '(value: string) => void' is not assignable to type '"a" | "b" | ((value: string) => boolean) | undefined'.
2+
Type '(value: string) => void' is not assignable to type '(value: string) => boolean'.
3+
Type 'void' is not assignable to type 'boolean'.
4+
tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx(43,41): error TS2322: Type '(value: string) => void' is not assignable to type '"a" | "b" | ((value: string) => boolean) | undefined'.
5+
Type '(value: string) => void' is not assignable to type '(value: string) => boolean'.
6+
Type 'void' is not assignable to type 'boolean'.
7+
tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx(64,37): error TS2322: Type '(value: string) => void' is not assignable to type '(value: string) => boolean'.
48
Type 'void' is not assignable to type 'boolean'.
59

610

7-
==== tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx (2 errors) ====
11+
==== tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx (3 errors) ====
812
/// <reference path="/.lib/react16.d.ts" />
913

1014
import React from 'react';
1115

1216
interface BaseProps {
13-
when?: (value: string) => boolean;
17+
when?: ((value: string) => boolean) | "a" | "b";
18+
error?: boolean;
1419
}
1520

1621
interface Props extends BaseProps {
@@ -32,10 +37,31 @@ tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx(48,37): error TS2322:
3237
// Error: Void not assignable to boolean
3338
const Test2 = () => <FieldFeedback when={value => console.log(value)} />;
3439
~~~~
35-
!!! error TS2322: Type '(value: string) => void' is not assignable to type '(value: string) => boolean'.
36-
!!! error TS2322: Type 'void' is not assignable to type 'boolean'.
37-
!!! 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>>'
40+
!!! error TS2322: Type '(value: string) => void' is not assignable to type '"a" | "b" | ((value: string) => boolean) | undefined'.
41+
!!! error TS2322: Type '(value: string) => void' is not assignable to type '(value: string) => boolean'.
42+
!!! error TS2322: Type 'void' is not assignable to type 'boolean'.
43+
!!! 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" | "error"> & Partial<Pick<Readonly<{ children?: ReactNode; }> & Readonly<Props>, "when">> & Partial<Pick<{ when: () => boolean; }, never>>'
44+
45+
class FieldFeedbackBeta<P extends Props = BaseProps> extends React.Component<P> {
46+
static defaultProps: BaseProps = {
47+
when: () => true
48+
};
49+
50+
render() {
51+
return <div>Hello</div>;
52+
}
53+
}
3854

55+
// OK
56+
const Test1a = () => <FieldFeedbackBeta when={value => !!value} error>Hah</FieldFeedbackBeta>;
57+
58+
// Error: Void not assignable to boolean
59+
const Test2a = () => <FieldFeedbackBeta when={value => console.log(value)} error>Hah</FieldFeedbackBeta>;
60+
~~~~
61+
!!! error TS2322: Type '(value: string) => void' is not assignable to type '"a" | "b" | ((value: string) => boolean) | undefined'.
62+
!!! error TS2322: Type '(value: string) => void' is not assignable to type '(value: string) => boolean'.
63+
!!! error TS2322: Type 'void' is not assignable to type 'boolean'.
64+
!!! related TS6500 tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx:6:3: The expected type comes from property 'when' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<FieldFeedbackBeta<Props>> & Pick<Readonly<{ children?: ReactNode; }> & Readonly<Props>, "children"> & Partial<Pick<Readonly<{ children?: ReactNode; }> & Readonly<Props>, "when" | "error">> & Partial<Pick<BaseProps, never>>'
3965

4066
interface MyPropsProps extends Props {
4167
when: (value: string) => boolean;
@@ -60,7 +86,7 @@ tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx(48,37): error TS2322:
6086
~~~~
6187
!!! error TS2322: Type '(value: string) => void' is not assignable to type '(value: string) => boolean'.
6288
!!! error TS2322: Type 'void' is not assignable to type 'boolean'.
63-
!!! 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>>'
89+
!!! related TS6500 tests/cases/compiler/reactDefaultPropsInferenceSuccess.tsx:46: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" | "error"> & Partial<Pick<Readonly<{ children?: ReactNode; }> & Readonly<MyPropsProps>, "when">> & Partial<Pick<{ when: () => boolean; }, never>>'
6490

6591
// OK
6692
const Test5 = () => <FieldFeedback2 />;

tests/baselines/reference/reactDefaultPropsInferenceSuccess.js

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import React from 'react';
55

66
interface BaseProps {
7-
when?: (value: string) => boolean;
7+
when?: ((value: string) => boolean) | "a" | "b";
8+
error?: boolean;
89
}
910

1011
interface Props extends BaseProps {
@@ -26,6 +27,21 @@ const Test1 = () => <FieldFeedback when={value => !!value} />;
2627
// Error: Void not assignable to boolean
2728
const Test2 = () => <FieldFeedback when={value => console.log(value)} />;
2829

30+
class FieldFeedbackBeta<P extends Props = BaseProps> extends React.Component<P> {
31+
static defaultProps: BaseProps = {
32+
when: () => true
33+
};
34+
35+
render() {
36+
return <div>Hello</div>;
37+
}
38+
}
39+
40+
// OK
41+
const Test1a = () => <FieldFeedbackBeta when={value => !!value} error>Hah</FieldFeedbackBeta>;
42+
43+
// Error: Void not assignable to boolean
44+
const Test2a = () => <FieldFeedbackBeta when={value => console.log(value)} error>Hah</FieldFeedbackBeta>;
2945

3046
interface MyPropsProps extends Props {
3147
when: (value: string) => boolean;
@@ -90,6 +106,23 @@ var FieldFeedback = /** @class */ (function (_super) {
90106
var Test1 = function () { return react_1["default"].createElement(FieldFeedback, { when: function (value) { return !!value; } }); };
91107
// Error: Void not assignable to boolean
92108
var Test2 = function () { return react_1["default"].createElement(FieldFeedback, { when: function (value) { return console.log(value); } }); };
109+
var FieldFeedbackBeta = /** @class */ (function (_super) {
110+
__extends(FieldFeedbackBeta, _super);
111+
function FieldFeedbackBeta() {
112+
return _super !== null && _super.apply(this, arguments) || this;
113+
}
114+
FieldFeedbackBeta.prototype.render = function () {
115+
return react_1["default"].createElement("div", null, "Hello");
116+
};
117+
FieldFeedbackBeta.defaultProps = {
118+
when: function () { return true; }
119+
};
120+
return FieldFeedbackBeta;
121+
}(react_1["default"].Component));
122+
// OK
123+
var Test1a = function () { return react_1["default"].createElement(FieldFeedbackBeta, { when: function (value) { return !!value; }, error: true }, "Hah"); };
124+
// Error: Void not assignable to boolean
125+
var Test2a = function () { return react_1["default"].createElement(FieldFeedbackBeta, { when: function (value) { return console.log(value); }, error: true }, "Hah"); };
93126
var FieldFeedback2 = /** @class */ (function (_super) {
94127
__extends(FieldFeedback2, _super);
95128
function FieldFeedback2() {

0 commit comments

Comments
 (0)