无星的前端之旅(十八)-Vue3+ts常见问题

第一次用Vue3+ts,采用了eslint(aribnb),遇到了一些问题,又不想用常常性使用any,只能逼迫本身解决问题。javascript

本文只是记录一些本身遇到的检测问题html

1.使用less并导出变量到ts使用,可是ts报错找不到

报错内容:vue

Cannot find module 'xxx.less' or its corresponding type declarations.
复制代码

解决方法:java

CSS in Typescriptios

2.setup中获取proxy,但提示可能为null

const { proxy } = getCurrentInstance();
复制代码

提示报错内容:git

Property 'proxy' does not exist on type 'ComponentInternalInstance | null'.
复制代码

解决方法:github

1.直接强制确认,由于毫无疑问,在页面或组件中,CurrentInstance必定存在,所以可使用!强制标记存在vue-cli

但在aribnb的eslint规则下,仍然会报警告typescript

const { proxy } = getCurrentInstance()!;
复制代码

2.使用as强转express

import { ComponentInternalInstance } from 'vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
复制代码

3.如何使用ref获取dom节点

<template>
  <div :ref="setDivRef" />
</template>
<script lang="ts"> import { defineComponent, ref } from 'vue'; export default defineComponent({ setup() { const divRef = ref<HTMLElement>(); const setDivRef = (el: HTMLElement) => { divRef.value = el; }; return { setDivRef, }; }, }); </script> 复制代码

4.若是使用Element-Plus的form组件,使用resetFields或者validate方法时,提示没有该属性

报错内容:

Property 'resetFields' does not exist on type 'HTMLElement'
Property 'validate' does not exist on type 'HTMLElement'
复制代码

解决方法:

使用InstanceType<typeof ElForm>做为范型约束

<template>
  <!-- 表单 -->
  <el-form :model="form" :ref="setFormRef" label-width="100px"> <!-- 注释 --> </el-form>
</template>

<script lang="ts">
import { ElForm } from 'element-plus';
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const formRef = ref<InstanceType<typeof ElForm>>();
    const setFormRef = (el: InstanceType<typeof ElForm>) => {
      formRef.value = el;
    };

    const resetForm = () => {
      formRef.value?.resetFields();
    };
    const confirm = () => {
      formRef.value?.validate((valid) => {
        if (valid) {
          // do
        }
      });
    };
    return {
      setFormRef,
      resetForm,
      confirm,
      formRef,
    };
  },
});
</script>

复制代码

参考:

Treffen人事管理项目记录

Vue.js の Composition API における this.$refs の取得方法

6.props中已经加上约束,可是在setup中使用仍是在报错

报错内容:

Property 'xxx' does not exist on type 'Readonly<{ [x: number]: string; } & { length?: number | undefined; toString?: string | undefined; toLocaleString?: string | undefined; concat?: string[] | undefined; join?: string | undefined; slice?: string[] | undefined; ... 16 more ...; flat?: unknown[] | undefined; }> | Readonly<...>'.
  Property 'xxx' does not exist on type 'Readonly<{ [x: number]: string; } & { length?: number | undefined; toString?: string | undefined; toLocaleString?: string | undefined; concat?: string[] | undefined; join?: string | undefined; slice?: string[] | undefined; ... 16 more ...; flat?: unknown[] | undefined; }>'.
复制代码

解决方法:

额外添加一个interface,名字任意,并将setup的props参数类型标记为定义类型

<script lang="ts">
import {
  computed,
  defineComponent,
} from 'vue';

interface Props1 {
  modelValue: boolean;
  loading: boolean;
}
export default defineComponent({
  props: {
    modelValue: {
      type: Boolean,
      default: false,
    },
    loading: {
      type: Boolean,
      default: false,
    },
  },
  setup(props: Props1, context) {
    const visible = computed({
      get: () => props.modelValue,
    });
    const loadingnow = computed({
      get: () => props.loading,
    });

    return {
      visible,
      loadingnow,
    };
  },
});
</script>

复制代码

7.如何给template加上ts类型推断

解决方法:

使用vscode,并添加vetur插件>0.29.0版本,在配置中添加

vetur.experimental.templateInterpolationService: true
复制代码

参考: 木子李的回答

8.在‘no-unused-expressions’的eslint规则下,常常将?.这个判断是否存在的语法糖标记为eslint错误

(实际上?这个语法糖,除了ts,js在ES2020中也支持了,因此我以为这个判读机制该升级了)

例如:

const foo = bar && bar.tea && bar.tea.cup;
//简写为
const foo = bar?.tea?.cup;
复制代码

报错内容:

Expected an assignment or function call and instead saw an expression. eslint(no-unused-expressions)
复制代码

解决方法:

若是是使用vue-cli建立的项目,默认会引入'@typescript-eslint'

在eslint配置规则中,关闭'no-unused-expressions',开启'@typescript-eslint/no-unused-expressions'

'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': 'error',
复制代码

参考:

Typescript optional chaining and ESLint no-unused-expressions

9.添加全局挂载属性,好比axios

挂载代码:

//main.ts
import axios from 'axios';
app.config.globalProperties.$api = axios;
复制代码

使用代码:

setup(){
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
proxy.$api.xxx
}
复制代码

会发现根本没有任何提示,而且会报错

解决方法:

新建一个xxx.d.ts声明文件,并在tsconfig中引入(可使用include,也可使用typeRoots等,主要看本身项目配置和路径)。

import { AxiosInstance } from 'axios';

declare module '@vue/runtime-core' {
  interface ComponentCustomProperties {
    $api: AxiosInstance;
  }
}

复制代码

参考: componentPublicInstance.ts#L41-L66

p.s:由于我对axios作了二次封装,我全部的api都写在一个文件里,相似:

// api.ts
export default {
	login:()=> axios.get(xxx,xxx),
	xxx
}
复制代码

这种,有n个接口,而且随着项目变更,我目前是手动写了一个d.ts,描述了一个interface,相似

// api.d.ts
export interface Api{
	login:()=>{}
    xxx
    xxx
    xxx
}
复制代码

这样,可是每新增一个接口,或者变更,我就要手动添加声明。请问有没有什么办法能把我解放出来TAT。

由于依赖了比较多的东西,我使用tsc命令单独为这个文件生成d.ts的时候会报错,没法生成。

求个答案,大佬们都是怎么作的。

相关文章
相关标签/搜索