在Vue 3中使用Typescript和Jsx

本文将介绍如何在Vue 3中使用tsx

首先回答两个问题:

Why Vue 3


在Vue 2中,组件相关的逻辑都被写在一个文件中,经常会出现一个组件几千行代码,非常难以维护;而且一个功能的相关代码通常会分散写在data methods created等各个选项中,想要复用一个功能也是比较困难的。而Vue 3的组合式API正是为了解决这个问题。

Why tsx


Vue中的组件是一个黑盒,你不知道他的内部结构(属性和事件),只能通过文档甚至阅读源码来了解,这样是很耗费时间的。而在tsx中,在编写代码时就可以获得代码提示,组件的内部结构可以一目了然,且具有代码约束力(当你编写了错误的代码时会获得一个报错),这样是可以极大的提高代码编写效率,减少低级错误出现。

组件的类型声明


Props

ts会从vue组件的props声明中推断属性的类型,以下是一些基本的类型推断:

  • String → string
  • Number → number
  • Boolean → boolean
  • Array → unknown[]
  • Object → Record
  • Date → string
  • Function → Function
  • Symbol → symbol

你可以通过PropType来进行更加精确的类型声明,建议对所有的Array Object Function都进行声明

import { defineComponent, PropType } from 'vue'
export default defineComponent({
  props: {
    title: String,
    values: {
      type: Array as PropType,
      required: true,
    },
    data: Object as PropType<{ id: number, name: string }>,
    onClick: Function as PropType<(id: number) => void>
  }
})

属性默认是可选的,在上面例子中的title默认会得到一个string | undefined的类型。如果你声明了required: true,他的类型就会变成string

有一些第三方组件可能会缺少类型声明,这会导致typescript类型检查错误***属性并不存在,这种情况建议使用属性解构,避开typescript类型检查

// Property 'onClick' does not exist on type ...


// 使用属性解构

Events

Events实际上是function props的语法糖,@click="myCallback"等价于onClick={myCallback}强烈建议避免使用Event,而使用与之等效的方法属性,这样你会获得更好的类型提示。

defineComponent({
  emits: {
    // event runtime validation
    'play': (value: string) => {
      return true
    },
    'rest-time': () => true
  },
  setup(props, {emit}) {
    onMounted(() => {
      emit('play', 'game')
      emit('rest-time')
    })
  }
})

等价于

defineComponent({
  props: {
    onPlay: Function as PropType<(value: string) => void>,
    'onRest-time': Function as PropType<() => void>,
  },
  setup(props) {
    onMounted(() => {
      props.onPlay('game')
      props['onRest-time']()
    })
  }
})

TSX语法


你可以继续使用template模板,不过我们更建议你使用tsx模板。


或者

Attributes / Props

// template


// tsx

Directives

v-model

// template





// tsx





// bind ref value

v-models

// template


// tsx

slot

const A = (props, { slots }) => (
  <>
    

{ slots.default ? slots.default() : 'foo' }

{ slots.bar && slots.bar() }

); const App = { setup() { const slots = { default: () =>
A
, bar: () => B, }; return () =>
; }, };

Hooks


Hooks是从React借鉴过来的概念,Vue 3中的Hooks叫做组合式API,它包括Vue 3提供的响应性api(ref, reactive, computed, onMounted...),以及自己编写的hook函数。

Hooks可以对混乱的代码做逻辑拆分,相似的功能可以方便的进行复用,通过Hooks的灵活组合,可以轻松处理大型复杂组件。

以下是Vue官网的例子,组件的功能被拆分到不同的Hooks中。

setup(props) {
  const { user } = toRefs(props)

  const { repositories, getUserRepositories } = useUserRepositories(user)

  const { searchQuery, repositoriesMatchingSearchQuery } = useRepositoryNameSearch(repositories)

  const { filters, updateFilters, filteredRepositories } = useRepositoryFilters(repositoriesMatchingSearchQuery)

  return {
    repositories: filteredRepositories,
    getUserRepositories,
    searchQuery,
    filters,
    updateFilters
  }
}

在React中,使用Hooks时需要遵守一些规则。不过Vue 3的渲染机制不同于React,在Vue 3中使用Hooks规则稍有不同:

1. 只在最顶层使用 Hook, 不要在循环,条件或嵌套函数中调用 Hook

由于Vue 3使用Proxy来追踪数据改变,Hooks调用的顺序不会影响数据的依赖关系,所以这条规则不必遵守。

2. 只在 React(Setup 和 Hook) 函数中调用 Hook,不要在普通的 JavaScript 函数中调用 Hook

这条规则仍然适用于Vue 3。Hooks可以用来保存状态,而普通函数不可以。当数据依赖改变时,函数会被重新执行,如果刚好函数中声明了一些状态,例如ref对象,那么这个状态就会被重置,从而导致意外的情况发生。所以Hook只能在Setup函数以及其他Hook中调用。

// ❎ 不要在普通函数中调用hook(ref)
function renderInput() {
  // 当input重新渲染时,inputValue会被重置
  const inputValue = ref('')
  return 
}
// ✅ 在setup中调用hook(ref)
setup() {
  const inputValue = ref('')
  return (
    {renderInput(inputValue)}
  )
}

// 通过参数传递inputValue
function renderInput(inputValue) {
  return 
}

Problems


目前,Vue 3对ts的支持度还没有达到100%,所以仍存在一些问题,例如:

  1. tsx代码无法热更新,需手动刷新(截至2021/4/30)

  2. 函数形式的属性默认值会干扰typescript类型推断,需改为箭头函数(截至2021/4/30)

    // ❎ 会干扰typescript类型推断
    export default defineComponent({
      props: {
     objectProp: {
       type: Object,
       default() {
         return {}
       }
     },
     arrayProp: {
       type: Array,
       default() {
         return []
       }
     }
      }
    })
    
    // ✅ 使用箭头函数
    export default defineComponent({
      props: {
     objectProp: {
       type: Object,
       default: () => ({})
     },
     arrayProp: {
       type: Array,
       default: () => []
     }
      }
    })

References


  1. Vue 3 typescript支持 (https://v3.cn.vuejs.org/guide/typescript-support.html)
  2. jsx-next repo (https://github.com/vuejs/jsx-next)
  3. Vue 3 组合式api (https://v3.cn.vuejs.org/guide/composition-api-introduction.html)

你可能感兴趣的:(在Vue 3中使用Typescript和Jsx)