提问人:Kauê Zuquetto 提问时间:10/11/2023 最后编辑:Kauê Zuquetto 更新时间:10/13/2023 访问量:58
自定义 hook vue3 composable 的声明文件
declaration file for custom hook vue3 composable
问:
我有一个 laravel、vue3 和 typescript 项目。
在用户模块 UsersGrid 中,我有一个自定义可组合项 useUser ,我想输入它,但是我尝试的每一种方式,总是会出现错误
作为自定义钩子(可组合)我无法 npm install @types/XYZ
根目录中的 tsconfig:
{
"compilerOptions": {
// As long as you are using a build tool, we recommend you to author and ship in ES modules.
// Even if you are targeting Node.js, because
// - `CommonJS` is too outdated
// - the ecosystem hasn't fully caught up with `Node16`/`NodeNext`
// This recommendation includes environments like Vitest, Vite Config File, Vite SSR, etc.
"module": "ESNext",
// We expect users to use bundlers.
// So here we enable some resolution features that are only available in bundlers.
"moduleResolution": "bundler",
"resolveJsonModule": true,
// `allowImportingTsExtensions` can only be used when `noEmit` or `emitDeclarationOnly` is set.
// But `noEmit` may cause problems with solution-style tsconfigs:
// <https://github.com/microsoft/TypeScript/issues/49844>
// And `emitDeclarationOnly` is not always wanted.
// Considering it's not likely to be commonly used in Vue codebases, we don't enable it here.
// Required in Vue projects
"jsx": "preserve",
"jsxImportSource": "vue",
// `"noImplicitThis": true` is part of `strict`
// Added again here in case some users decide to disable `strict`.
// This enables stricter inference for data properties on `this`.
"noImplicitThis": true,
"strict": true,
// <https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#verbatimmodulesyntax>
// Any imports or exports without a type modifier are left around. This is important for `<script setup>`.
// Anything that uses the type modifier is dropped entirely.
"verbatimModuleSyntax": true,
// A few notes:
// - Vue 3 supports ES2016+
// - For Vite, the actual compilation target is determined by the
// `build.target` option in the Vite config.
// So don't change the `target` field here. It has to be
// at least `ES2020` for dynamic `import()`s and `import.meta` to work correctly.
// - If you are not using Vite, feel free to overwrite the `target` field.
"target": "ESNext",
// For spec compilance.
// `true` by default if the `target` is `ES2020` or higher.
// Explicitly set it to `true` here in case some users want to overwrite the `target`.
"useDefineForClassFields": true,
// Recommended
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
// See <https://github.com/vuejs/vue-cli/pull/5688>
"skipLibCheck": true,
}
}
用户网格:
<template>
<div>
<ag-grid-vue :style="gridStyle" suppressHorizontalScroll="true" :gridOptions="gridOptions" :class="gridMode"
:columnDefs="columnDefs.value" :rowData="rowData" :loadingOverlayComponent="CardOverlay">
</ag-grid-vue>
</div>
</template>
<script setup lang="ts">
import { ref, watch, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router';
import { AgGridVue } from "ag-grid-vue3";
import { useI18n } from 'vue-i18n'
import { gridOptions, gridStyle } from "../../helpers/gridSettings";
import ActionButtons from '../../components/grids/ActionButtons.vue'
import CardOverlay from '../../components/general/CardOverlay.vue'
import Tr from "../../helpers/translation";
import useUser from '../../composables/useUser' // Could not find a declaration file for module '../../composables/useUser'. 'c:/Users/kaue.zuquetto/Desktop/Dev/Portal/resources/js/composables/useUser.js' implicitly has an 'any' type.
import { useStore } from 'vuex'
import type { User, ColDef } from '../../../../types'
const { t, locale } = useI18n()
const store = useStore()
const router = useRouter()
const gridMode = ref('ag-theme-alpine')
const columnDefs = ref()
const {
getAllData: getUsers,
deleteData: deleteUser,
rowData,
} = useUser();
const details = (id: number) => {
router.push(Tr.i18nRoute({ name: 'user.read', params: { id } }))
}
const i18nGrid = () => {
columnDefs.value = [
[],
{ headerName: 'ID', field: 'id', flex: 1 },
{ headerName: t('user.grid.colName'), field: 'name', flex: 3 },
{ headerName: t('user.grid.colEmail'), field: 'email', flex: 3 },
{ headerName: t('grid.created_at'), field: 'created_at', flex: 3 },
{ headerName: t('grid.updated_at'), field: 'updated_at', flex: 3 },
{
headerName: '',
flex: 1.5,
sortable: false,
filter: false,
cellRenderer: ActionButtons,
cellRendererParams: function () {
return {
details: details,
delete: deleteUser,
id: arguments[0].data.id,
buttons: ['details', 'delete']
}
},
},
] as ColDef<User>[];
}
const options = computed(() => {
return store.getters["preferences/options"]
})
watch(options, () => {
gridMode.value = store.state.preferences.options.grid
})
watch(locale, () => {
i18nGrid()
})
onMounted(() => {
i18nGrid()
getUsers()
gridMode.value = store.state.preferences.options.grid
})
</script>
我的使用用户可组合:
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import useSwal from '../helpers/swal'
import Tr from '../helpers/translation'
import { gridOptions, gridStyle } from "../helpers/gridSettings"
const { confirm_delete_swal, toast_success, toast_error } = useSwal()
const useUser = (userID = null) => {
const router = useRouter()
const user = ref({})
const isLoading = ref(false)
const processing = ref(false)
const errors = ref(false)
const rowData = ref(null)
const getAllData = async () => {
try {
const response = await axios.get('/api/users')
const { status } = response
if (status === 200) {
rowData.value = response.data.data
rowData.value.sort((a, b) => b.id - a.id)
} else {
console.log('ERROR STATUS: ' + response.status)
toast_error()
}
} catch (e) {
gridOptions.api.hideOverlay()
gridOptions.api.showNoRowsOverlay()
toast_error()
console.log(e)
}
}
const getData = async () => {
try {
isLoading.value = true
const url = '/api/user/' + userID + '/read';
const response = await axios.get(url)
if (response.status === 200) {
const { data } = response.data
user.value = data
} else {
console.log('ERROR STATUS: ' + response.status)
toast_error()
}
} catch (e) {
toast_error()
console.log(e)
} finally {
isLoading.value = false
}
}
const createData = async (formData) => {
try {
processing.value = true
const response = await axios.post('/api/user/create', formData)
if (response.status === 200) {
const { data } = response.data
errors.value = {}
router.push(Tr.i18nRoute({ name: 'user.read', params: { id: data.id } }))
toast_success()
} else {
toast_error()
console.log('ERROR STATUS: ' + response.status)
}
} catch (e) {
toast_error()
console.log(e)
if (e.response && e.response.data.errors) {
errors.value = e.response.data.errors
}
} finally {
processing.value = false
}
}
const updateData = async (formData, userRoles) => {
try {
processing.value = true
const response = await axios.put('/api/user/' + userID + '/update', formData)
if (response.status === 200) {
const { data } = response.data
errors.value = {}
router.replace(Tr.i18nRoute({ name: 'user.read', params: { id: data } }))
userRoles.assignRoles()
} else {
toast_error()
console.log('ERROR STATUS: ' + response.status)
}
} catch (e) {
toast_error()
console.log(e)
toast_error()
if (e.response && e.response.data.errors) {
errors.value = e.response.data.errors
}
} finally {
processing.value = false
}
}
const deleteData = async (id) => {
try {
const { isConfirmed } = await confirm_delete_swal(id)
if (isConfirmed) {
const response = await axios.delete('/api/user/' + id + '/delete')
const { status } = response
if (status == 200) {
getAllData()
toast_success()
} else {
toast_error()
}
}
} catch (e) {
toast_error()
console.log(e)
if (e.response && e.response.data.errors) {
errors.value = e.response.data.errors
}
}
}
userID ? getData() : ''
return {
getAllData,
rowData,
getData,
user,
createData,
updateData,
deleteData,
isLoading,
processing,
errors,
}
}
export default useUser;
如何从我的 useUser 钩子创建声明文件?它总是抱怨不是一个模块,或者不可调用
useUser.d.ts :
找不到模块 '.. 的声明文件。/../composables/useUser“。隐式具有“任何”type.ts(7016)
declare module 'useUser' {
export function useUser(): unknown
}
答:
1赞
yoduh
10/13/2023
#1
除非另有配置,否则 TypeScript 文件(或组件)仅需要类型化导入。您的可组合项是一个文件。您可以更改此行为并允许使用 tsconfig 中的 allowJs 编译器选项导入.js
"compilerOptions": {
"allowJs": true,
}
或者,您可以在 TypeScript 中重写可组合项。
评论
0赞
Kauê Zuquetto
10/16/2023
我明白,但是在某些库的情况下,它是如何工作的?例如,我使用vue-i18n,有vue-i18n.d.js和vue-i18n.d.ts的文件,一个只有一个声明(声明文件),另一个只有JS,我怎样才能做出这样的声明文件?是否可以在不将 useUser 文件迁移到 .ts 的情况下?提前感谢您的帮助
0赞
yoduh
10/16/2023
大多数 TS 库也与 JS 兼容,因为编译步骤将打字稿拆分为 .js 和 .d.ts 文件,这些文件是发布的。这两个文件可以在 TS 项目中一起使用,也可以在 JS 项目中单独使用 .js 文件。通常,只需在 TS 中编写代码并让编译步骤创建声明文件会更容易,但您也可以根据需要手动创建一个声明文件,或者使用工具
0赞
Kauê Zuquetto
10/17/2023
非常感谢,感谢您抽出宝贵时间帮助我,我设法更好地理解,我认为必须同时拥有两种类型的文件。现在我要将 js 迁移到 ts
评论