diff --git a/package.json b/package.json
index fccb0ae..0c47ad7 100644
--- a/package.json
+++ b/package.json
@@ -1,4 +1,5 @@
{
+ "type": "module",
"name": "@coreui/coreui-free-react-admin-template",
"version": "5.5.0",
"description": "CoreUI Free React Admin Template",
@@ -27,6 +28,11 @@
"@coreui/react-chartjs": "^3.0.0",
"@coreui/utils": "^2.0.2",
"@popperjs/core": "^2.11.8",
+ "@types/jest": "^30.0.0",
+ "@types/node": "^25.0.3",
+ "@types/prop-types": "^15.7.15",
+ "@types/react": "^19.2.7",
+ "@types/react-dom": "^19.2.3",
"chart.js": "^4.5.1",
"classnames": "^2.5.1",
"core-js": "^3.47.0",
@@ -36,7 +42,8 @@
"react-redux": "^9.2.0",
"react-router-dom": "^7.11.0",
"redux": "5.0.1",
- "simplebar-react": "^3.3.2"
+ "simplebar-react": "^3.3.2",
+ "typescript": "^5.9.3"
},
"devDependencies": {
"@vitejs/plugin-react": "^5.1.2",
diff --git a/src/App.js b/src/App.tsx
similarity index 72%
rename from src/App.js
rename to src/App.tsx
index f5b2239..93554bf 100644
--- a/src/App.js
+++ b/src/App.tsx
@@ -1,6 +1,7 @@
import React, { Suspense, useEffect } from 'react'
import { HashRouter, Route, Routes } from 'react-router-dom'
import { useSelector } from 'react-redux'
+import { RootState } from './store'
import { CSpinner, useColorModes } from '@coreui/react'
import './scss/style.scss'
@@ -19,11 +20,11 @@ const Page500 = React.lazy(() => import('./views/pages/page500/Page500'))
const App = () => {
const { isColorModeSet, setColorMode } = useColorModes('coreui-free-react-admin-template-theme')
- const storedTheme = useSelector((state) => state.theme)
+ const storedTheme = useSelector((state: RootState) => state.theme)
useEffect(() => {
const urlParams = new URLSearchParams(window.location.href.split('?')[1])
- const theme = urlParams.get('theme') && urlParams.get('theme').match(/^[A-Za-z0-9\s]+/)[0]
+ const theme = urlParams.get('theme')?.match(/^[A-Za-z0-9\s]+/)?.[0]
if (theme) {
setColorMode(theme)
}
@@ -45,11 +46,11 @@ const App = () => {
}
>
- } />
- } />
- } />
- } />
- } />
+ } />
+ } />
+ } />
+ } />
+ } />
diff --git a/src/_nav.js b/src/_nav.tsx
similarity index 100%
rename from src/_nav.js
rename to src/_nav.tsx
diff --git a/src/assets/brand/logo.js b/src/assets/brand/logo.ts
similarity index 100%
rename from src/assets/brand/logo.js
rename to src/assets/brand/logo.ts
diff --git a/src/assets/brand/sygnet.js b/src/assets/brand/sygnet.ts
similarity index 100%
rename from src/assets/brand/sygnet.js
rename to src/assets/brand/sygnet.ts
diff --git a/src/components/AppBreadcrumb.js b/src/components/AppBreadcrumb.tsx
similarity index 100%
rename from src/components/AppBreadcrumb.js
rename to src/components/AppBreadcrumb.tsx
diff --git a/src/components/AppContent.js b/src/components/AppContent.tsx
similarity index 91%
rename from src/components/AppContent.js
rename to src/components/AppContent.tsx
index b9a39ef..ef4424e 100644
--- a/src/components/AppContent.js
+++ b/src/components/AppContent.tsx
@@ -16,8 +16,6 @@ const AppContent = () => {
}
/>
)
diff --git a/src/components/AppFooter.js b/src/components/AppFooter.tsx
similarity index 100%
rename from src/components/AppFooter.js
rename to src/components/AppFooter.tsx
diff --git a/src/components/AppHeader.js b/src/components/AppHeader.tsx
similarity index 96%
rename from src/components/AppHeader.js
rename to src/components/AppHeader.tsx
index 4db98af..40db829 100644
--- a/src/components/AppHeader.js
+++ b/src/components/AppHeader.tsx
@@ -1,6 +1,7 @@
import React, { useEffect, useRef } from 'react'
import { NavLink } from 'react-router-dom'
import { useSelector, useDispatch } from 'react-redux'
+import { RootState } from '../store'
import {
CContainer,
CDropdown,
@@ -29,11 +30,11 @@ import { AppBreadcrumb } from './index'
import { AppHeaderDropdown } from './header/index'
const AppHeader = () => {
- const headerRef = useRef()
+ const headerRef = useRef(null)
const { colorMode, setColorMode } = useColorModes('coreui-free-react-admin-template-theme')
const dispatch = useDispatch()
- const sidebarShow = useSelector((state) => state.sidebarShow)
+ const sidebarShow = useSelector((state: RootState) => state.sidebarShow)
useEffect(() => {
const handleScroll = () => {
diff --git a/src/components/AppSidebar.js b/src/components/AppSidebar.tsx
similarity index 84%
rename from src/components/AppSidebar.js
rename to src/components/AppSidebar.tsx
index 021cb52..d75d4a9 100644
--- a/src/components/AppSidebar.js
+++ b/src/components/AppSidebar.tsx
@@ -1,5 +1,7 @@
import React from 'react'
+import { NavLink } from 'react-router-dom'
import { useSelector, useDispatch } from 'react-redux'
+import { RootState } from '../store'
import {
CCloseButton,
@@ -21,8 +23,8 @@ import navigation from '../_nav'
const AppSidebar = () => {
const dispatch = useDispatch()
- const unfoldable = useSelector((state) => state.sidebarUnfoldable)
- const sidebarShow = useSelector((state) => state.sidebarShow)
+ const unfoldable = useSelector((state: RootState) => state.sidebarUnfoldable)
+ const sidebarShow = useSelector((state: RootState) => state.sidebarShow)
return (
{
}}
>
-
+
diff --git a/src/components/AppSidebarNav.js b/src/components/AppSidebarNav.tsx
similarity index 100%
rename from src/components/AppSidebarNav.js
rename to src/components/AppSidebarNav.tsx
diff --git a/src/components/DocsComponents.js b/src/components/DocsComponents.tsx
similarity index 100%
rename from src/components/DocsComponents.js
rename to src/components/DocsComponents.tsx
diff --git a/src/components/DocsExample.js b/src/components/DocsExample.tsx
similarity index 100%
rename from src/components/DocsExample.js
rename to src/components/DocsExample.tsx
diff --git a/src/components/DocsIcons.js b/src/components/DocsIcons.tsx
similarity index 100%
rename from src/components/DocsIcons.js
rename to src/components/DocsIcons.tsx
diff --git a/src/components/DocsLink.js b/src/components/DocsLink.tsx
similarity index 100%
rename from src/components/DocsLink.js
rename to src/components/DocsLink.tsx
diff --git a/src/components/header/AppHeaderDropdown.js b/src/components/header/AppHeaderDropdown.tsx
similarity index 100%
rename from src/components/header/AppHeaderDropdown.js
rename to src/components/header/AppHeaderDropdown.tsx
diff --git a/src/components/header/index.js b/src/components/header/index.tsx
similarity index 100%
rename from src/components/header/index.js
rename to src/components/header/index.tsx
diff --git a/src/components/index.js b/src/components/index.ts
similarity index 100%
rename from src/components/index.js
rename to src/components/index.ts
diff --git a/src/images.d.ts b/src/images.d.ts
new file mode 100644
index 0000000..9b87a51
--- /dev/null
+++ b/src/images.d.ts
@@ -0,0 +1,19 @@
+declare module '*.webp' {
+ const src: string;
+ export default src;
+}
+
+declare module '*.png' {
+ const src: string;
+ export default src;
+}
+
+declare module '*.jpg' {
+ const src: string;
+ export default src;
+}
+
+declare module '*.svg' {
+ const src: string;
+ export default src;
+}
\ No newline at end of file
diff --git a/src/index.js b/src/index.tsx
similarity index 81%
rename from src/index.js
rename to src/index.tsx
index 11d6e86..441af3a 100644
--- a/src/index.js
+++ b/src/index.tsx
@@ -6,7 +6,7 @@ import 'core-js'
import App from './App'
import store from './store'
-createRoot(document.getElementById('root')).render(
+createRoot(document.getElementById('root')!).render(
,
diff --git a/src/layout/DefaultLayout.js b/src/layout/DefaultLayout.tsx
similarity index 100%
rename from src/layout/DefaultLayout.js
rename to src/layout/DefaultLayout.tsx
diff --git a/src/routes.js b/src/routes.ts
similarity index 100%
rename from src/routes.js
rename to src/routes.ts
diff --git a/src/store.js b/src/store.js
deleted file mode 100644
index 8ad30da..0000000
--- a/src/store.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { legacy_createStore as createStore } from 'redux'
-
-const initialState = {
- sidebarShow: true,
- theme: 'light',
-}
-
-const changeState = (state = initialState, { type, ...rest }) => {
- switch (type) {
- case 'set':
- return { ...state, ...rest }
- default:
- return state
- }
-}
-
-const store = createStore(changeState)
-export default store
diff --git a/src/store.tsx b/src/store.tsx
new file mode 100644
index 0000000..5edafef
--- /dev/null
+++ b/src/store.tsx
@@ -0,0 +1,33 @@
+import { legacy_createStore as createStore } from 'redux'
+
+// 상태(State) 타입 정의
+interface AppState {
+ sidebarShow: boolean
+ sidebarUnfoldable: boolean
+ theme: string
+}
+
+const initialState: AppState = {
+ sidebarShow: true,
+ sidebarUnfoldable: false,
+ theme: 'light',
+}
+
+// 액션(Action) 타입 정의
+interface Action {
+ type: string
+ [key: string]: any
+}
+
+const changeState = (state = initialState, { type, ...rest }: Action): AppState => {
+ switch (type) {
+ case 'set':
+ return { ...state, ...rest }
+ default:
+ return state
+ }
+}
+
+const store = createStore(changeState)
+export type RootState = ReturnType
+export default store
diff --git a/src/styles.d.ts b/src/styles.d.ts
new file mode 100644
index 0000000..7cbc819
--- /dev/null
+++ b/src/styles.d.ts
@@ -0,0 +1,4 @@
+declare module '*.scss' {
+ const content: { [className: string]: string };
+ export default content;
+}
\ No newline at end of file
diff --git a/src/views/dashboard/Dashboard.js b/src/views/dashboard/Dashboard.tsx
similarity index 100%
rename from src/views/dashboard/Dashboard.js
rename to src/views/dashboard/Dashboard.tsx
diff --git a/src/views/dashboard/MainChart.js b/src/views/dashboard/MainChart.tsx
similarity index 100%
rename from src/views/dashboard/MainChart.js
rename to src/views/dashboard/MainChart.tsx
diff --git a/src/views/pages/login/Login.js b/src/views/pages/login/Login.tsx
similarity index 100%
rename from src/views/pages/login/Login.js
rename to src/views/pages/login/Login.tsx
diff --git a/src/views/pages/page404/Page404.js b/src/views/pages/page404/Page404.tsx
similarity index 100%
rename from src/views/pages/page404/Page404.js
rename to src/views/pages/page404/Page404.tsx
diff --git a/src/views/pages/page500/Page500.js b/src/views/pages/page500/Page500.tsx
similarity index 100%
rename from src/views/pages/page500/Page500.js
rename to src/views/pages/page500/Page500.tsx
diff --git a/src/views/pages/register/Register.js b/src/views/pages/register/Register.tsx
similarity index 100%
rename from src/views/pages/register/Register.js
rename to src/views/pages/register/Register.tsx
diff --git a/src/views/theme/colors/Colors.js b/src/views/theme/colors/Colors.tsx
similarity index 100%
rename from src/views/theme/colors/Colors.js
rename to src/views/theme/colors/Colors.tsx
diff --git a/src/views/theme/typography/Typography.js b/src/views/theme/typography/Typography.tsx
similarity index 100%
rename from src/views/theme/typography/Typography.js
rename to src/views/theme/typography/Typography.tsx
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..c349a5e
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,31 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "target": "ES5",
+ "strict": true,
+ "allowJs": true,
+ "esModuleInterop": true,
+ "jsx": "react-jsx",
+ // Stricter Typechecking Options
+ "noUncheckedIndexedAccess": true,
+ "exactOptionalPropertyTypes": true,
+ // Style Options
+ // "noImplicitReturns": true,
+ // "noImplicitOverride": true,
+ // "noUnusedLocals": true,
+ // "noUnusedParameters": true,
+ // "noFallthroughCasesInSwitch": true,
+ // "noPropertyAccessFromIndexSignature": true,
+ // Recommended Options
+ "verbatimModuleSyntax": false,
+ "isolatedModules": true,
+ "noUncheckedSideEffectImports": true,
+ "moduleDetection": "force",
+ "skipLibCheck": true,
+ },
+ "include": [
+ "src",
+ "src/images.d.ts",
+ "src/styles.d.ts"
+ ]
+}
\ No newline at end of file
diff --git a/vite.config.mjs b/vite.config.mjs
index dc050f7..7766fd3 100644
--- a/vite.config.mjs
+++ b/vite.config.mjs
@@ -16,11 +16,6 @@ export default defineConfig(() => {
],
},
},
- esbuild: {
- loader: 'jsx',
- include: /src\/.*\.jsx?$/,
- exclude: [],
- },
optimizeDeps: {
force: true,
esbuildOptions: {
@@ -33,7 +28,7 @@ export default defineConfig(() => {
resolve: {
alias: [
{
- find: 'src/',
+ find: 'src',
replacement: `${path.resolve(__dirname, 'src')}/`,
},
],