Skip to content

Commit 8a36e76

Browse files
committed
refactor: migrate src/ to TypeScript (#809)
* build: add tsx files as targets of Babel * refactor: migrate ChildMapping to TypeScript * refactor: add types for TransitionGroupContext * refactor: migrate SwitchTransition to TypeScript * refactor: migrate Transition to TypeScript * refactor: migrate CSSTransition to TypeScript * refactor: migrate TransitionGroup to TypeScript * refactor: migrate ReplaceTransition to TypeScript * chore: update size-snapshot
1 parent 52d612f commit 8a36e76

12 files changed

+523
-331
lines changed

.size-snapshot.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{
22
"lib/dist/react-transition-group.js": {
3-
"bundled": 98066,
4-
"minified": 26272,
5-
"gzipped": 8027
3+
"bundled": 101943,
4+
"minified": 26331,
5+
"gzipped": 8046
66
},
77
"lib/dist/react-transition-group.min.js": {
8-
"bundled": 55134,
9-
"minified": 17999,
10-
"gzipped": 5654
8+
"bundled": 58919,
9+
"minified": 18068,
10+
"gzipped": 5664
1111
}
1212
}

.storybook/main.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,18 @@ module.exports = {
44
stories: ['../stories/index.js'],
55
webpackFinal: (config) => {
66
config.module = {
7-
rules: [rules.js(), rules.astroturf(), rules.css({ extract: false })],
7+
rules: [
8+
{
9+
test: /\.[t|j]sx?$/,
10+
exclude: /node_modules/,
11+
use: {
12+
loader: 'babel-loader',
13+
},
14+
},
15+
rules.astroturf(),
16+
rules.css({ extract: false }),
17+
],
818
};
9-
1019
config.plugins.push(plugins.extractCss({ disable: true }));
1120

1221
return config;

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
"@typescript-eslint/eslint-plugin": "^4.26.1",
9090
"astroturf": "^0.10.4",
9191
"babel-eslint": "^10.1.0",
92-
"babel-loader": "^8.1.0",
92+
"babel-loader": "^8.2.3",
9393
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
9494
"babel-preset-jason": "^6.2.0",
9595
"cherry-pick": "^0.5.0",

rollup.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const globals = {
1414

1515
const babelOptions = {
1616
exclude: /node_modules/,
17+
extensions: ['.js', '.ts', '.tsx'],
1718
runtimeHelpers: true,
1819
};
1920

src/CSSTransition.js renamed to src/CSSTransition.tsx

+50-15
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,32 @@ import addOneClass from 'dom-helpers/addClass';
44
import removeOneClass from 'dom-helpers/removeClass';
55
import React from 'react';
66

7-
import Transition from './Transition';
7+
import Transition, { Props as TransitionProps } from './Transition';
88
import { classNamesShape } from './utils/PropTypes';
99

10-
const addClass = (node, classes) =>
10+
const addClass = (node: HTMLElement, classes: string) =>
1111
node && classes && classes.split(' ').forEach((c) => addOneClass(node, c));
12-
const removeClass = (node, classes) =>
12+
const removeClass = (node: HTMLElement, classes: string) =>
1313
node && classes && classes.split(' ').forEach((c) => removeOneClass(node, c));
1414

15+
type TransitionClassNames = {
16+
appear: string;
17+
appearActive: string;
18+
appearDone: string;
19+
enter: string;
20+
enterActive: string;
21+
enterDone: string;
22+
exit: string;
23+
exitActive: string;
24+
exitDone: string;
25+
};
26+
27+
type Props = TransitionProps & {
28+
classNames: string | Partial<TransitionClassNames>;
29+
};
30+
31+
type TransitionClassNameKeys = 'appear' | 'enter' | 'exit';
32+
1533
/**
1634
* A transition component inspired by the excellent
1735
* [ng-animate](https://docs.angularjs.org/api/ngAnimate) library, you should
@@ -81,7 +99,7 @@ const removeClass = (node, classes) =>
8199
* [`appear`](http://reactcommunity.org/react-transition-group/transition#Transition-prop-appear)
82100
* prop, make sure to define styles for `.appear-*` classes as well.
83101
*/
84-
class CSSTransition extends React.Component {
102+
class CSSTransition extends React.Component<Props> {
85103
static defaultProps = {
86104
classNames: '',
87105
};
@@ -92,7 +110,7 @@ class CSSTransition extends React.Component {
92110
exit: {},
93111
};
94112

95-
onEnter = (maybeNode, maybeAppearing) => {
113+
onEnter = (maybeNode: HTMLElement | boolean, maybeAppearing?: boolean) => {
96114
const [node, appearing] = this.resolveArguments(maybeNode, maybeAppearing);
97115
this.removeClasses(node, 'exit');
98116
this.addClass(node, appearing ? 'appear' : 'enter', 'base');
@@ -102,7 +120,7 @@ class CSSTransition extends React.Component {
102120
}
103121
};
104122

105-
onEntering = (maybeNode, maybeAppearing) => {
123+
onEntering = (maybeNode: HTMLElement | boolean, maybeAppearing?: boolean) => {
106124
const [node, appearing] = this.resolveArguments(maybeNode, maybeAppearing);
107125
const type = appearing ? 'appear' : 'enter';
108126
this.addClass(node, type, 'active');
@@ -112,7 +130,7 @@ class CSSTransition extends React.Component {
112130
}
113131
};
114132

115-
onEntered = (maybeNode, maybeAppearing) => {
133+
onEntered = (maybeNode: HTMLElement | boolean, maybeAppearing?: boolean) => {
116134
const [node, appearing] = this.resolveArguments(maybeNode, maybeAppearing);
117135
const type = appearing ? 'appear' : 'enter';
118136
this.removeClasses(node, type);
@@ -123,7 +141,7 @@ class CSSTransition extends React.Component {
123141
}
124142
};
125143

126-
onExit = (maybeNode) => {
144+
onExit = (maybeNode?: HTMLElement) => {
127145
const [node] = this.resolveArguments(maybeNode);
128146
this.removeClasses(node, 'appear');
129147
this.removeClasses(node, 'enter');
@@ -134,7 +152,7 @@ class CSSTransition extends React.Component {
134152
}
135153
};
136154

137-
onExiting = (maybeNode) => {
155+
onExiting = (maybeNode?: HTMLElement) => {
138156
const [node] = this.resolveArguments(maybeNode);
139157
this.addClass(node, 'exit', 'active');
140158

@@ -143,7 +161,7 @@ class CSSTransition extends React.Component {
143161
}
144162
};
145163

146-
onExited = (maybeNode) => {
164+
onExited = (maybeNode?: HTMLElement) => {
147165
const [node] = this.resolveArguments(maybeNode);
148166
this.removeClasses(node, 'exit');
149167
this.addClass(node, 'exit', 'done');
@@ -154,12 +172,16 @@ class CSSTransition extends React.Component {
154172
};
155173

156174
// when prop `nodeRef` is provided `node` is excluded
157-
resolveArguments = (maybeNode, maybeAppearing) =>
175+
resolveArguments = (
176+
maybeNode: HTMLElement | boolean | undefined,
177+
maybeAppearing?: boolean
178+
): [HTMLElement, boolean] =>
179+
// @ts-expect-error FIXME: Type at position 1 in source is not compatible with type at position 1 in target. Type 'boolean | HTMLElement' is not assignable to type 'boolean'. Type 'HTMLElement' is not assignable to type 'boolean'.ts(2322)
158180
this.props.nodeRef
159181
? [this.props.nodeRef.current, maybeNode] // here `maybeNode` is actually `appearing`
160182
: [maybeNode, maybeAppearing]; // `findDOMNode` was used
161183

162-
getClassNames = (type) => {
184+
getClassNames = (type: TransitionClassNameKeys) => {
163185
const { classNames } = this.props;
164186
const isStringClassNames = typeof classNames === 'string';
165187
const prefix = isStringClassNames && classNames ? `${classNames}-` : '';
@@ -183,7 +205,11 @@ class CSSTransition extends React.Component {
183205
};
184206
};
185207

186-
addClass(node, type, phase) {
208+
addClass(
209+
node: HTMLElement | null,
210+
type: TransitionClassNameKeys,
211+
phase: 'base' | 'active' | 'done'
212+
) {
187213
let className = this.getClassNames(type)[`${phase}ClassName`];
188214
const { doneClassName } = this.getClassNames('enter');
189215

@@ -194,32 +220,40 @@ class CSSTransition extends React.Component {
194220
// This is to force a repaint,
195221
// which is necessary in order to transition styles when adding a class name.
196222
if (phase === 'active') {
197-
/* eslint-disable no-unused-expressions */
223+
/* eslint-disable no-unused-expressions, @typescript-eslint/no-unused-expressions */
198224
node && node.scrollTop;
199225
}
200226

201227
if (className) {
228+
// @ts-expect-error FIXME: Property 'active' does not exist on type '{} | {} | {}'.ts(7053)
202229
this.appliedClasses[type][phase] = className;
230+
// @ts-expect-error FIXME: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.ts(2345)
203231
addClass(node, className);
204232
}
205233
}
206234

207-
removeClasses(node, type) {
235+
removeClasses(node: HTMLElement | null, type: TransitionClassNameKeys) {
208236
const {
237+
// @ts-expect-error FIXME: Property 'base' does not exist on type '{} | {} | {}'.ts(2339)
209238
base: baseClassName,
239+
// @ts-expect-error FIXME: Property 'active' does not exist on type '{} | {} | {}'.ts(2339)
210240
active: activeClassName,
241+
// @ts-expect-error FIMXE: Property 'done' does not exist on type '{} | {} | {}'.ts(2339)
211242
done: doneClassName,
212243
} = this.appliedClasses[type];
213244

214245
this.appliedClasses[type] = {};
215246

216247
if (baseClassName) {
248+
// @ts-expect-error FIXME: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.ts(2345)
217249
removeClass(node, baseClassName);
218250
}
219251
if (activeClassName) {
252+
// @ts-expect-error FIXME: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.ts(2345)
220253
removeClass(node, activeClassName);
221254
}
222255
if (doneClassName) {
256+
// @ts-expect-error FIXME: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.ts(2345)
223257
removeClass(node, doneClassName);
224258
}
225259
}
@@ -241,6 +275,7 @@ class CSSTransition extends React.Component {
241275
}
242276
}
243277

278+
// @ts-expect-error To make TS migration diffs minimum, I've left propTypes here instead of defining a static property
244279
CSSTransition.propTypes = {
245280
...Transition.propTypes,
246281

src/ReplaceTransition.js renamed to src/ReplaceTransition.tsx

+23-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import PropTypes from 'prop-types';
22
import React from 'react';
3+
import type { ReactElement } from 'react';
34
import ReactDOM from 'react-dom';
45
import TransitionGroup from './TransitionGroup';
6+
import type { Props as TransitionProps } from './Transition';
7+
8+
type Props = Omit<TransitionProps, 'children'> & {
9+
children: [ReactElement<TransitionProps>, ReactElement<TransitionProps>];
10+
};
511

612
/**
713
* The `<ReplaceTransition>` component is a specialized `Transition` component
@@ -14,32 +20,35 @@ import TransitionGroup from './TransitionGroup';
1420
* </ReplaceTransition>
1521
* ```
1622
*/
17-
class ReplaceTransition extends React.Component {
18-
handleEnter = (...args) => this.handleLifecycle('onEnter', 0, args);
19-
handleEntering = (...args) => this.handleLifecycle('onEntering', 0, args);
20-
handleEntered = (...args) => this.handleLifecycle('onEntered', 0, args);
23+
class ReplaceTransition extends React.Component<Props> {
24+
handleEnter = (...args: any) => this.handleLifecycle('onEnter', 0, args);
25+
handleEntering = (...args: any) =>
26+
this.handleLifecycle('onEntering', 0, args);
27+
handleEntered = (...args: any) => this.handleLifecycle('onEntered', 0, args);
2128

22-
handleExit = (...args) => this.handleLifecycle('onExit', 1, args);
23-
handleExiting = (...args) => this.handleLifecycle('onExiting', 1, args);
24-
handleExited = (...args) => this.handleLifecycle('onExited', 1, args);
29+
handleExit = (...args: any) => this.handleLifecycle('onExit', 1, args);
30+
handleExiting = (...args: any) => this.handleLifecycle('onExiting', 1, args);
31+
handleExited = (...args: any) => this.handleLifecycle('onExited', 1, args);
2532

26-
handleLifecycle(handler, idx, originalArgs) {
33+
handleLifecycle(handler: any, idx: number, originalArgs: any) {
2734
const { children } = this.props;
28-
const child = React.Children.toArray(children)[idx];
35+
// @ts-expect-error FIXME: Type 'string' is not assignable to type 'ReactElement<Props, string | JSXElementConstructor<any>>'.ts(2322)
36+
const child: ChildElement = React.Children.toArray(children)[idx];
2937

3038
if (child.props[handler]) child.props[handler](...originalArgs);
39+
// @ts-expect-error Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'Readonly<Props> & Readonly<{ children?: ReactNode; }>'.ts(7053)
3140
if (this.props[handler]) {
3241
const maybeNode = child.props.nodeRef
3342
? undefined
3443
: ReactDOM.findDOMNode(this);
35-
44+
// @ts-expect-error FIXME: Argument of type 'Element | Text | null | undefined' is not assignable to parameter of type 'HTMLElement'.ts(2769)
3645
this.props[handler](maybeNode);
3746
}
3847
}
3948

4049
render() {
41-
const { children, in: inProp, ...props } = this.props;
42-
const [first, second] = React.Children.toArray(children);
50+
const { children, in: inProp, ...props }: any = this.props;
51+
const [first, second]: any = React.Children.toArray(children);
4352

4453
delete props.onEnter;
4554
delete props.onEntering;
@@ -68,9 +77,10 @@ class ReplaceTransition extends React.Component {
6877
}
6978
}
7079

80+
// @ts-expect-error To make TS migration diffs minimum, I've left propTypes here instead of defining a static property
7181
ReplaceTransition.propTypes = {
7282
in: PropTypes.bool.isRequired,
73-
children(props, propName) {
83+
children(props: any, propName: any) {
7484
if (React.Children.count(props[propName]) !== 2)
7585
return new Error(
7686
`"${propName}" must be exactly two transition components.`

0 commit comments

Comments
 (0)