Skip to content

Commit 45b5dca

Browse files
committed
Convert to TypeScript (#122)
1 parent 0f1d880 commit 45b5dca

22 files changed

+490
-206
lines changed

.babelrc

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,3 @@
11
{
2-
"presets": ["@babel/env", "@babel/react"],
3-
"env": {
4-
"production-esm": {
5-
"presets": [
6-
[
7-
"@babel/env",
8-
{
9-
"modules": false
10-
}
11-
],
12-
"@babel/react"
13-
]
14-
}
15-
}
2+
"presets": ["@babel/typescript", "@babel/env", "@babel/react"]
163
}

.eslintrc.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
{
2-
"extends": "wojtekmaj/react-no-automatic-runtime",
2+
"extends": [
3+
"wojtekmaj/react-no-automatic-runtime",
4+
"plugin:@typescript-eslint/eslint-recommended",
5+
"plugin:@typescript-eslint/recommended"
6+
],
7+
"parser": "@typescript-eslint/parser",
8+
"plugins": ["@typescript-eslint"],
39
"overrides": [
410
{
511
"files": ["sample/**", "test/**"],
612
"rules": {
13+
"@typescript-eslint/no-var-requires": "off",
714
"import/no-unresolved": "off"
815
}
916
}

package.json

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,25 @@
44
"description": "An analog clock for your React app.",
55
"main": "dist/cjs/index.js",
66
"module": "dist/esm/index.js",
7-
"source": "src/index.js",
7+
"source": "src/index.ts",
8+
"types": "dist/cjs/index.d.ts",
89
"sideEffects": [
910
"*.css"
1011
],
1112
"scripts": {
1213
"build": "yarn build-js && yarn copy-styles",
1314
"build-js": "yarn build-js-esm && yarn build-js-cjs",
14-
"build-js-esm": "BABEL_ENV=production-esm babel src -d dist/esm --ignore \"**/*.spec.js,**/*.spec.jsx\"",
15-
"build-js-cjs": "BABEL_ENV=production-cjs babel src -d dist/cjs --ignore \"**/*.spec.js,**/*.spec.jsx\"",
15+
"build-js-esm": "tsc --project tsconfig.build.json --outDir dist/esm --module esnext",
16+
"build-js-cjs": "tsc --project tsconfig.build.json --outDir dist/cjs --module commonjs",
1617
"clean": "rimraf dist",
1718
"copy-styles": "node ./copy-styles.mjs",
1819
"jest": "jest",
19-
"lint": "eslint . --ext .js,.jsx",
20+
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
2021
"postinstall": "husky install",
2122
"prepack": "yarn clean && yarn build",
2223
"prettier": "prettier --check . --cache",
23-
"test": "yarn lint && yarn prettier && yarn jest"
24+
"test": "yarn lint && yarn tsc && yarn prettier && yarn jest",
25+
"tsc": "tsc --noEmit"
2426
},
2527
"keywords": [
2628
"clock",
@@ -41,18 +43,22 @@
4143
],
4244
"license": "MIT",
4345
"dependencies": {
44-
"@wojtekmaj/date-utils": "^1.0.0",
46+
"@types/react": "*",
47+
"@wojtekmaj/date-utils": "^1.1.2",
4548
"clsx": "^1.2.1",
4649
"get-user-locale": "^2.0.0",
4750
"prop-types": "^15.6.0"
4851
},
4952
"devDependencies": {
50-
"@babel/cli": "^7.15.0",
5153
"@babel/core": "^7.15.0",
5254
"@babel/preset-env": "^7.15.0",
5355
"@babel/preset-react": "^7.14.0",
56+
"@babel/preset-typescript": "^7.18.6",
5457
"@testing-library/jest-dom": "^5.15.0",
5558
"@testing-library/react": "^13.4.0",
59+
"@types/jest": "^29.0.0",
60+
"@typescript-eslint/eslint-plugin": "^5.41.0",
61+
"@typescript-eslint/parser": "^5.44.0",
5662
"eslint": "^8.26.0",
5763
"eslint-config-wojtekmaj": "^0.7.1",
5864
"husky": "^8.0.0",
@@ -62,7 +68,8 @@
6268
"pretty-quick": "^3.1.0",
6369
"react": "^18.2.0",
6470
"react-dom": "^18.2.0",
65-
"rimraf": "^3.0.0"
71+
"rimraf": "^3.0.0",
72+
"typescript": "^4.9.4"
6673
},
6774
"peerDependencies": {
6875
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",

src/Clock.spec.jsx renamed to src/Clock.spec.tsx

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ describe('Clock', () => {
8686
const hourMarks = container.querySelectorAll('.react-clock__hour-mark');
8787

8888
hourMarks.forEach((hourMark, index) => {
89-
expect(hourMark).toHaveTextContent(index + 1);
89+
expect(hourMark).toHaveTextContent(`${index + 1}`);
9090
});
9191
});
9292

@@ -137,8 +137,25 @@ describe('Clock', () => {
137137
const minuteSecondAngle = minuteAngle / 60;
138138
const secondAngle = fullCircle / 60;
139139

140-
const getDeg = (transform) => parseFloat(transform.match(/rotate\(([0-9.]*)deg\)/)[1]);
141-
const getAngle = (hand) => getDeg(window.getComputedStyle(hand).transform) % 360;
140+
function getDeg(transform: string) {
141+
const match = transform.match(/rotate\(([0-9.]*)deg\)/);
142+
143+
if (!match) {
144+
throw new Error('Could not parse transform');
145+
}
146+
147+
const deg = match[1];
148+
149+
if (!deg) {
150+
throw new Error('Could not parse transform');
151+
}
152+
153+
return parseFloat(deg);
154+
}
155+
156+
function getAngle(hand: HTMLElement) {
157+
return getDeg(window.getComputedStyle(hand).transform) % 360;
158+
}
142159

143160
describe('hour hand', () => {
144161
it('is rendered properly', () => {
@@ -156,7 +173,7 @@ describe('Clock', () => {
156173

157174
const { container } = render(<Clock value={date} />);
158175

159-
const hand = container.querySelector('.react-clock__hour-hand');
176+
const hand = container.querySelector('.react-clock__hour-hand') as HTMLDivElement;
160177

161178
expect(getAngle(hand)).toBeCloseTo(hour * hourAngle + minute * hourMinuteAngle);
162179
});
@@ -187,7 +204,7 @@ describe('Clock', () => {
187204

188205
const { container } = render(<Clock value={date} />);
189206

190-
const hand = container.querySelector('.react-clock__minute-hand');
207+
const hand = container.querySelector('.react-clock__minute-hand') as HTMLDivElement;
191208

192209
expect(getAngle(hand)).toBeCloseTo(minute * minuteAngle + second * minuteSecondAngle);
193210
});
@@ -218,7 +235,7 @@ describe('Clock', () => {
218235

219236
const { container } = render(<Clock value={date} />);
220237

221-
const hand = container.querySelector('.react-clock__second-hand');
238+
const hand = container.querySelector('.react-clock__second-hand') as HTMLDivElement;
222239

223240
expect(getAngle(hand)).toBeCloseTo(second * secondAngle);
224241
});

src/Clock.jsx renamed to src/Clock.tsx

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import Hand from './Hand';
77
import MinuteMark from './MinuteMark';
88
import HourMark from './HourMark';
99

10+
import type { formatHour as defaultFormatHour } from './shared/hourFormatter';
11+
1012
import {
1113
isHandLength,
1214
isOppositeHandLength,
@@ -15,6 +17,40 @@ import {
1517
isMarkWidth,
1618
} from './shared/propTypes';
1719

20+
import type {
21+
HandLength,
22+
HandWidth,
23+
MarkLength,
24+
MarkWidth,
25+
OppositeHandLength,
26+
} from './shared/types';
27+
28+
type ClockProps = {
29+
className?: string;
30+
formatHour?: typeof defaultFormatHour;
31+
hourHandLength?: HandLength;
32+
hourHandOppositeLength?: OppositeHandLength;
33+
hourHandWidth?: HandWidth;
34+
hourMarksLength?: MarkLength;
35+
hourMarksWidth?: MarkWidth;
36+
locale?: string;
37+
minuteHandLength?: HandLength;
38+
minuteHandOppositeLength?: OppositeHandLength;
39+
minuteHandWidth?: HandWidth;
40+
minuteMarksLength?: MarkLength;
41+
minuteMarksWidth?: MarkWidth;
42+
renderHourMarks?: boolean;
43+
renderMinuteHand?: boolean;
44+
renderMinuteMarks?: boolean;
45+
renderNumbers?: boolean;
46+
renderSecondHand?: boolean;
47+
secondHandLength?: HandLength;
48+
secondHandOppositeLength?: OppositeHandLength;
49+
secondHandWidth?: HandWidth;
50+
size?: React.CSSProperties['width'];
51+
value?: string | Date;
52+
};
53+
1854
export default function Clock({
1955
className,
2056
formatHour,
@@ -39,7 +75,7 @@ export default function Clock({
3975
secondHandWidth = 1,
4076
size = 150,
4177
value,
42-
}) {
78+
}: ClockProps) {
4379
function renderMinuteMarksFn() {
4480
if (!renderMinuteMarks) {
4581
return null;
@@ -79,7 +115,7 @@ export default function Clock({
79115
length={hourMarksLength}
80116
locale={locale}
81117
name="hour"
82-
number={renderNumbers ? i : null}
118+
number={renderNumbers ? i : undefined}
83119
width={hourMarksWidth}
84120
/>,
85121
);
File renamed without changes.

src/Hand.jsx renamed to src/Hand.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
33

4-
import { isHandLength } from './shared/propTypes';
4+
import { isHandLength, isHandWidth } from './shared/propTypes';
55

6-
export default function Hand({ angle = 0, name, length = 100, oppositeLength = 10, width = 1 }) {
6+
import type { HandLength, HandWidth, OppositeHandLength } from './shared/types';
7+
8+
type HandProps = {
9+
angle?: number;
10+
length?: HandLength;
11+
name: string;
12+
oppositeLength?: OppositeHandLength;
13+
width?: HandWidth;
14+
};
15+
16+
export default function Hand({
17+
angle = 0,
18+
name,
19+
length = 100,
20+
oppositeLength = 10,
21+
width = 1,
22+
}: HandProps) {
723
return (
824
<div
925
className={`react-clock__hand react-clock__${name}-hand`}
@@ -28,5 +44,5 @@ Hand.propTypes = {
2844
length: isHandLength,
2945
name: PropTypes.string.isRequired,
3046
oppositeLength: isHandLength,
31-
width: PropTypes.number,
47+
width: isHandWidth,
3248
};
File renamed without changes.

src/HourMark.jsx renamed to src/HourMark.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,23 @@ import Mark from './Mark';
55

66
import { formatHour as defaultFormatHour } from './shared/hourFormatter';
77

8+
type HourMarkProps = React.ComponentProps<typeof Mark> & {
9+
formatHour?: typeof defaultFormatHour;
10+
locale?: string;
11+
number?: number;
12+
};
13+
814
export default function HourMark({
915
formatHour = defaultFormatHour,
1016
locale,
1117
number,
1218
...otherProps
13-
}) {
19+
}: HourMarkProps) {
1420
return <Mark number={number && formatHour(locale, number)} {...otherProps} />;
1521
}
1622

1723
HourMark.propTypes = {
1824
formatHour: PropTypes.func,
1925
locale: PropTypes.string,
20-
number: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
26+
number: PropTypes.number,
2127
};
File renamed without changes.

0 commit comments

Comments
 (0)