1
1
import PropTypes from 'prop-types' ;
2
2
import React from 'react' ;
3
+ import type { ReactElement , ReactChild } from 'react' ;
3
4
import TransitionGroupContext from './TransitionGroupContext' ;
4
5
5
6
import {
@@ -8,11 +9,32 @@ import {
8
9
getNextChildMapping ,
9
10
} from './utils/ChildMapping' ;
10
11
11
- const values = Object . values || ( ( obj ) => Object . keys ( obj ) . map ( ( k ) => obj [ k ] ) ) ;
12
+ const values =
13
+ Object . values ||
14
+ ( ( obj : Record < string , unknown > ) => Object . keys ( obj ) . map ( ( k ) => obj [ k ] ) ) ;
12
15
13
16
const defaultProps = {
14
17
component : 'div' ,
15
- childFactory : ( child ) => child ,
18
+ childFactory : ( child : ReactElement ) => child ,
19
+ } ;
20
+
21
+ type Props = {
22
+ component : any ;
23
+ children : any ;
24
+ appear : boolean ;
25
+ enter : boolean ;
26
+ exit : boolean ;
27
+ childFactory : ( child : ReactElement ) => ReactElement ;
28
+ } ;
29
+
30
+ type State = {
31
+ children : Record < string , ReactChild > ;
32
+ contextValue : { isMounting : boolean } ;
33
+ handleExited : (
34
+ child : ReactElement < { onExited : ( node : HTMLElement ) => void } > ,
35
+ node : HTMLElement
36
+ ) => void ;
37
+ firstRender : boolean ;
16
38
} ;
17
39
18
40
/**
@@ -29,13 +51,17 @@ const defaultProps = {
29
51
* component. This means you can mix and match animations across different list
30
52
* items.
31
53
*/
32
- class TransitionGroup extends React . Component {
33
- constructor ( props , context ) {
54
+ class TransitionGroup extends React . Component < Props , State > {
55
+ static defaultProps = defaultProps ;
56
+
57
+ mounted = false ;
58
+ constructor ( props : Props , context : any ) {
34
59
super ( props , context ) ;
35
60
36
61
const handleExited = this . handleExited . bind ( this ) ;
37
62
38
63
// Initial children should all be entering, dependent on appear
64
+ // @ts -expect-error FIXME: Property 'children' is missing in type '{ contextValue: { isMounting: true; }; handleExited: (child: React.ReactElement<{ onExited: (node: HTMLElement) => void; }, string | React.JSXElementConstructor<any>>, node: HTMLElement) => void; firstRender: true; }' but required in type 'Readonly<State>'.ts(2741)
39
65
this . state = {
40
66
contextValue : { isMounting : true } ,
41
67
handleExited,
@@ -55,8 +81,8 @@ class TransitionGroup extends React.Component {
55
81
}
56
82
57
83
static getDerivedStateFromProps (
58
- nextProps ,
59
- { children : prevChildMapping , handleExited, firstRender }
84
+ nextProps : Props ,
85
+ { children : prevChildMapping , handleExited, firstRender } : State
60
86
) {
61
87
return {
62
88
children : firstRender
@@ -67,10 +93,12 @@ class TransitionGroup extends React.Component {
67
93
}
68
94
69
95
// node is `undefined` when user provided `nodeRef` prop
70
- handleExited ( child , node ) {
96
+ handleExited (
97
+ child : ReactElement < { onExited : ( node : HTMLElement ) => void } > ,
98
+ node : HTMLElement
99
+ ) {
71
100
let currentChildMapping = getChildMapping ( this . props . children ) ;
72
-
73
- if ( child . key in currentChildMapping ) return ;
101
+ if ( child . key && child . key in currentChildMapping ) return ;
74
102
75
103
if ( child . props . onExited ) {
76
104
child . props . onExited ( node ) ;
@@ -79,8 +107,9 @@ class TransitionGroup extends React.Component {
79
107
if ( this . mounted ) {
80
108
this . setState ( ( state ) => {
81
109
let children = { ...state . children } ;
82
-
83
- delete children [ child . key ] ;
110
+ if ( child . key ) {
111
+ delete children [ child . key ] ;
112
+ }
84
113
return { children } ;
85
114
} ) ;
86
115
}
@@ -89,11 +118,14 @@ class TransitionGroup extends React.Component {
89
118
render ( ) {
90
119
const { component : Component , childFactory, ...props } = this . props ;
91
120
const { contextValue } = this . state ;
121
+ // @ts -expect-error FIXME: Type 'undefined' is not assignable to type 'ReactElement<any, string | JSXElementConstructor<any>>'.ts(2345)
92
122
const children = values ( this . state . children ) . map ( childFactory ) ;
93
-
94
- delete props . appear ;
95
- delete props . enter ;
96
- delete props . exit ;
123
+ const {
124
+ appear : _appear ,
125
+ enter : _enter ,
126
+ exit : _exit ,
127
+ ...delegatingProps
128
+ } = props ;
97
129
98
130
if ( Component === null ) {
99
131
return (
@@ -104,12 +136,13 @@ class TransitionGroup extends React.Component {
104
136
}
105
137
return (
106
138
< TransitionGroupContext . Provider value = { contextValue } >
107
- < Component { ...props } > { children } </ Component >
139
+ < Component { ...delegatingProps } > { children } </ Component >
108
140
</ TransitionGroupContext . Provider >
109
141
) ;
110
142
}
111
143
}
112
144
145
+ // @ts -expect-error To make TS migration diffs minimum, I've left propTypes here instead of defining a static property
113
146
TransitionGroup . propTypes = {
114
147
/**
115
148
* `<TransitionGroup>` renders a `<div>` by default. You can change this
@@ -166,6 +199,4 @@ TransitionGroup.propTypes = {
166
199
childFactory : PropTypes . func ,
167
200
} ;
168
201
169
- TransitionGroup . defaultProps = defaultProps ;
170
-
171
202
export default TransitionGroup ;
0 commit comments