diff --git a/.eslintrc.js b/.eslintrc.js
index 637d20c11..6e9ad3b47 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,8 +1,5 @@
 module.exports = {
   extends: ['plugin:markdown/recommended'],
-  rules: {
-    'no-void': 0
-  },
   overrides: [
     {
       files: 'src/**/*.vue',
@@ -38,7 +35,9 @@ module.exports = {
       },
       rules: {
         '@typescript-eslint/strict-boolean-expressions': 0,
-        '@typescript-eslint/prefer-nullish-coalescing': 0
+        '@typescript-eslint/prefer-nullish-coalescing': 0,
+        '@typescript-eslint/naming-convention': 0,
+        'no-void': 0
       }
     },
     {
diff --git a/.prettierignore b/.prettierignore
index acc77d333..4b0112c81 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1,2 +1,3 @@
 src/_deprecated/icons
 *.cssr.js
+*.cssr.ts
diff --git a/demo/utils/ComponentDemos.js b/demo/utils/ComponentDemos.js
index 176589382..81440279a 100644
--- a/demo/utils/ComponentDemos.js
+++ b/demo/utils/ComponentDemos.js
@@ -1,6 +1,6 @@
 import { h } from 'vue'
-import NCol from '../../src/grid/src/Col.vue'
-import NRow from '../../src/grid/src/Row.vue'
+import NCol from '../../src/grid/src/Col'
+import NRow from '../../src/grid/src/Row'
 
 export default {
   name: 'ComponentDemos',
diff --git a/package.json b/package.json
index 8515a473d..bfe1853f9 100644
--- a/package.json
+++ b/package.json
@@ -127,7 +127,7 @@
     "treemate": "^0.1.18",
     "vdirs": "^0.0.3",
     "vfonts": "^0.0.1",
-    "vooks": "^0.0.6",
+    "vooks": "0.0.8",
     "vue": "^3.0.5",
     "vueuc": "0.0.11"
   },
diff --git a/src/_mixins/use-theme.ts b/src/_mixins/use-theme.ts
index c1935473b..07cdbe8d7 100644
--- a/src/_mixins/use-theme.ts
+++ b/src/_mixins/use-theme.ts
@@ -12,11 +12,11 @@ globalStyle.mount({
   id: 'naive-ui-global'
 })
 
-export interface Theme<T, R = any> {
+export interface Theme<T = undefined, R = any> {
   name: string
   common?: ThemeCommonVars
   peers?: R
-  self(vars: ThemeCommonVars): T
+  self?: (vars: ThemeCommonVars) => T
 }
 
 type UseThemeProps<T> = Readonly<{
@@ -121,7 +121,7 @@ useTheme.props = {
   }
 } as const
 
-export type ThemeProps<T> = {
+export interface ThemeProps<T> {
   unstableTheme: {
     type: PropType<T>
     default: undefined
@@ -136,7 +136,7 @@ export type ThemeProps<T> = {
   }
 }
 
-export type ThemePropsReactive<T> = {
+export interface ThemePropsReactive<T> {
   unstableTheme: T
   unstableThemeOverrides: Record<string, any>
   builtinThemeOverrides: Record<string, any>
diff --git a/src/config-consumer/src/use-legacy.ts b/src/config-consumer/src/use-legacy.ts
index c9181ff8c..d1f0296c8 100644
--- a/src/config-consumer/src/use-legacy.ts
+++ b/src/config-consumer/src/use-legacy.ts
@@ -1,4 +1,4 @@
-import { computed, watch, toRef } from 'vue'
+import { computed, watch, toRef, ComputedRef } from 'vue'
 import { ConfigProviderInjection } from '../../config-provider'
 import styleScheme from '../../_deprecated/style-scheme'
 
@@ -9,11 +9,18 @@ interface UseLegacyProps {
   ) => void
 }
 
+interface UseLegacy {
+  legacyTheme: ComputedRef<string | undefined>
+  legacyLanguage: ComputedRef<string | undefined>
+  legacyThemeEnvironment: ComputedRef<any>
+  legacyStyleScheme: ComputedRef<any>
+}
+
 export default function useLegacy (
   NConfigProvider: ConfigProviderInjection | null,
-  props: UseLegacyProps
-) {
-  if (NConfigProvider) {
+  props?: UseLegacyProps
+): UseLegacy {
+  if (NConfigProvider && props) {
     watch(toRef(NConfigProvider, 'mergedLanguage'), (value, oldValue) => {
       const { onLanguageChange } = props
       if (onLanguageChange) onLanguageChange(value, oldValue)
@@ -21,10 +28,10 @@ export default function useLegacy (
   }
   return {
     legacyTheme: computed(() => {
-      return (NConfigProvider && NConfigProvider.mergedTheme) || 'light'
+      return NConfigProvider?.mergedTheme || 'light'
     }),
     legacyLanguage: computed(() => {
-      return NConfigProvider ? NConfigProvider.mergedLanguage : null
+      return NConfigProvider ? NConfigProvider.mergedLanguage : undefined
     }),
     legacyThemeEnvironment: computed(() => {
       const { mergedThemeEnvironments, mergedTheme } = NConfigProvider || {}
diff --git a/src/divider/index.ts b/src/divider/index.ts
index 222dd3818..98fe6e8c5 100644
--- a/src/divider/index.ts
+++ b/src/divider/index.ts
@@ -1,2 +1,2 @@
 /* istanbul ignore file */
-export { default as NDivider } from './src/Divider.vue'
+export { default as NDivider } from './src/Divider'
diff --git a/src/element/index.js b/src/element/index.ts
similarity index 100%
rename from src/element/index.js
rename to src/element/index.ts
diff --git a/src/element/src/Element.js b/src/element/src/Element.ts
similarity index 54%
rename from src/element/src/Element.js
rename to src/element/src/Element.ts
index b5030a23d..22226de7b 100644
--- a/src/element/src/Element.js
+++ b/src/element/src/Element.ts
@@ -1,6 +1,7 @@
-import { computed, h, defineComponent } from 'vue'
+import { computed, h, defineComponent, PropType } from 'vue'
 import { kebabCase } from 'lodash-es'
 import { useConfig, useTheme } from '../../_mixins'
+import type { ThemeProps } from '../../_mixins'
 import { warn } from '../../_utils'
 
 /**
@@ -8,26 +9,29 @@ import { warn } from '../../_utils'
  */
 import useLegacy from '../../config-consumer/src/use-legacy'
 import { elementLight } from '../styles'
+import type { ElementTheme } from '../styles'
 
 export default defineComponent({
   name: 'Element',
   alias: ['El'],
   props: {
-    ...useTheme.props,
+    ...(useTheme.props as ThemeProps<ElementTheme>),
     tag: {
       type: String,
       default: 'div'
     },
     // deprecated
     onThemeChange: {
-      validator () {
+      type: Function as PropType<(theme: string | undefined) => void>,
+      validator: () => {
         warn('element', '`on-theme-change` is deprecated.')
         return true
       },
       default: undefined
     },
     as: {
-      validator () {
+      type: String,
+      validator: () => {
         warn('element', '`as` is deprecated, please use `tag` instead.')
         return true
       },
@@ -35,13 +39,22 @@ export default defineComponent({
     }
   },
   setup (props) {
-    const themeRef = useTheme('Element', 'Element', null, elementLight, props)
+    const themeRef = useTheme(
+      'Element',
+      'Element',
+      undefined,
+      elementLight,
+      props
+    )
+    const { NConfigProvider, namespace } = useConfig(props)
     return {
-      ...useLegacy(props),
-      ...useConfig(props),
+      ...useLegacy(NConfigProvider),
+      namespace,
       cssVars: computed(() => {
         const { common } = themeRef.value
-        return Object.keys(common).reduce((prevValue, key) => {
+        return ((Object.keys(common) as unknown) as Array<
+        keyof typeof common
+        >).reduce<Record<string, string | number>>((prevValue, key) => {
           prevValue[`--${kebabCase(key)}`] = common[key]
           return prevValue
         }, {})
@@ -63,22 +76,15 @@ export default defineComponent({
     return h(
       as || tag,
       {
-        class: [
-          'n-element',
-          {
-            [`n-${legacyTheme}-theme`]: legacyTheme
-          }
-        ],
+        class: ['n-element', legacyTheme && `n-${legacyTheme}-theme`],
         style: cssVars
       },
-      ($slots.default &&
-        $slots.default({
-          namespace: namespace,
-          theme: legacyTheme,
-          themeEnvironment: legacyThemeEnvironment,
-          styleScheme: legacyStyleScheme
-        })) ||
-        null
+      ($slots.default?.({
+        namespace: namespace,
+        theme: legacyTheme,
+        themeEnvironment: legacyThemeEnvironment,
+        styleScheme: legacyStyleScheme
+      }) || null) as any
     )
   }
 })
diff --git a/src/element/styles/dark.js b/src/element/styles/dark.js
deleted file mode 100644
index 1dac9404d..000000000
--- a/src/element/styles/dark.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import { commonDark } from '../../_styles/new-common'
-
-export default {
-  name: 'Element',
-  common: commonDark
-}
diff --git a/src/element/styles/dark.ts b/src/element/styles/dark.ts
new file mode 100644
index 000000000..c7c9d3a19
--- /dev/null
+++ b/src/element/styles/dark.ts
@@ -0,0 +1,9 @@
+import { commonDark } from '../../_styles/new-common'
+import { ElementTheme } from './light'
+
+const elementDark: ElementTheme = {
+  name: 'Element',
+  common: commonDark
+}
+
+export default elementDark
diff --git a/src/element/styles/index.js b/src/element/styles/index.ts
similarity index 69%
rename from src/element/styles/index.js
rename to src/element/styles/index.ts
index 7a567b140..1ded1b717 100644
--- a/src/element/styles/index.js
+++ b/src/element/styles/index.ts
@@ -1,2 +1,3 @@
 export { default as elementDark } from './dark'
 export { default as elementLight } from './light'
+export type { ElementTheme } from './light'
diff --git a/src/element/styles/light.js b/src/element/styles/light.js
deleted file mode 100644
index 9291288ae..000000000
--- a/src/element/styles/light.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import { commonLight } from '../../_styles/new-common'
-
-export default {
-  name: 'Element',
-  common: commonLight
-}
diff --git a/src/element/styles/light.ts b/src/element/styles/light.ts
new file mode 100644
index 000000000..a85a8f431
--- /dev/null
+++ b/src/element/styles/light.ts
@@ -0,0 +1,10 @@
+import { Theme } from '../../_mixins'
+import { commonLight } from '../../_styles/new-common'
+
+const elementLight: Theme = {
+  name: 'Element',
+  common: commonLight
+}
+
+export default elementLight
+export type ElementTheme = typeof elementLight
diff --git a/src/global.d.ts b/src/global.d.ts
index 359ca76a2..5e279c2c9 100644
--- a/src/global.d.ts
+++ b/src/global.d.ts
@@ -1,5 +1,10 @@
+import { HTMLAttributes } from 'vue'
 export {}
 
 declare global {
   var __DEV__: boolean
-}
\ No newline at end of file
+}
+
+declare module 'vue' {
+  interface ComponentCustomProps extends HTMLAttributes {}
+}
diff --git a/src/grid/src/Row.tsx b/src/grid/src/Row.tsx
index 6e37c6f28..fd91143ed 100644
--- a/src/grid/src/Row.tsx
+++ b/src/grid/src/Row.tsx
@@ -10,7 +10,7 @@ import {
 import { useMemo } from 'vooks'
 import { formatLength } from '../../_utils'
 import { useStyle } from '../../_mixins'
-import style from './styles/index.cssr.js'
+import style from './styles/index.cssr'
 
 export interface RowInjection {
   gutter: any