無星的前端之旅(十八)-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的時候會報錯,沒法生成。

求個答案,大佬們都是怎麼作的。

相關文章
相關標籤/搜索