TS 在 Vue 中的应用
一、Vue 搭配 TS 应用
二、示例
1、Vue 模板 TS
<template>
  <button :class="cls" @click="handleClick">
    <i-icon class="i-button-icon" v-if="!!icon" :name="icon" />
    <slot />
  </button>
</template>
<script setup lang="ts">
import { computed } from 'vue'
interface ButtonProps {
  /**
   * 是否聚焦状态
   * @default false
   */
  active?: boolean
  /**
   * 是否禁用按钮
   * @default false
   */
  disabled?: boolean
  /**
   * 按钮形状
   * @default round
   */
  shape?: 'square' | 'round' | 'circle'
  /**
   * 按钮尺寸
   * @default medium
   */
  size?: 'small' | 'medium' | 'large'
  /**
   * 按钮类型,用于描述组件不同的应用场景
   * @default primary
   */
  type?: 'info' | 'primary' | 'error' | 'warning' | 'success'
  /**
   * 按钮形式
   * @default base
   */
  variant?: 'base' | 'outline' | 'dashed' | 'text'
  /**
   * 内置图标
   */
  icon?: string
}
interface ButtonEmits {
  /**
   * 点击事件
   */
  (type: 'click', e: MouseEvent): void
}
const {
  active = false,
  disabled = false,
  shape = 'round',
  size = 'medium',
  type = 'primary',
  variant = 'base',
  icon
} = defineProps<ButtonProps>()
const emit = defineEmits<ButtonEmits>()
const handleClick = (e: MouseEvent) => {
  if (disabled) {
    return
  }
  emit('click', e)
}
const cls = computed(() => [
  'i-button',
  `i-button--type-${type}`,
  variant !== 'base' && `i-button--variant-${variant}`,
  size !== 'medium' && `i-button--size-${size}`,
  shape !== 'round' && `i-button--shape-${shape}`,
  active && 'i-button-active',
  disabled && 'i-button-disabled'
])
</script>
<style lang="scss">
@import './index.scss';
</style>
2、Vue-JSX TS
import { defineComponent, PropType } from 'vue';
import './index.scss';
import { DropdownOption } from './type'
import { turnValue } from '../common'
import _ from 'lodash';
export default defineComponent({
  name: 'DropdownMenu',
  props: {
    /**
     * 下拉操作项
     * @default []
     */
    options: {
      type: Array as PropType<DropdownOption[]>,
      default: []
    },
    /**
     * 下拉列表宽度
     */
    width: [String, Number],
    /**
     * 下拉项高度
     * @default medium
     */
    size: String as PropType<'small' | 'medium' | 'large'>,
    /**
     * 级联子层级展开方向
     * @default right
     */
    cascaderDirection: {
      type: String as PropType<'left' | 'right'>,
      default: 'right'
    },
    /**
     * 是否可多选
     * @default false
     */
    multiple: {
      type: Boolean,
      default: false
    },
    /**
     * 选中值
     */
    selectedValue: {
      type: [String, Number, Array] as PropType<
        string |
        number |
        Array<string | number>
      >,
      default: []
    }
  },
  emits: {
    /**
     * 点击菜单项触发事件
     */
    'clickItem': (dropdownItem: DropdownOption, event: MouseEvent) => true
  },
  setup(props, { slots, emit }) {
    const handleItemClick = (item: DropdownOption, event: MouseEvent) => {
      event.stopPropagation()
      !(item.children && item.children?.length > 0) && emit('clickItem', item, event)
      item.onClick?.(item, event)
    }
    return () => {
      return (
        <ul
          class={[
            'i-dropdown__menu',
            props.cascaderDirection === 'left' && 'i-dropdown__menu-left'
          ]}
          style={{
            width: turnValue(props.width) ? turnValue(props.width) : 'auto',
            overflowY: props.maxHeight ? 'auto' : 'unset'
          }}
        >
          ...
        </ul>
      );
    };
  },
});