vue3实现props类型推导和默认值推导

854 阅读1分钟

组件

import { defineComponent, } from 'vue'
import props from './props'
export default defineComponent({
    name: 'MyComponent',
    props,
    setup(props, ctx) {
        return {
        }
    }
})

组件props

import { PropType } from "vue";

interface AddressInfo {
    province: string
    city: string
}
export default {
    studentId: {
        type: [String ,Number] as PropType<string | number>,
        default: ''
    },
    studentName: {
        type: String as PropType<string>,
        default: ''
    },
    addressInfo: {
        type: Object as PropType<AddressInfo>,
        default: () => {
            return {
                province: '山东',
                city: '淄博',
            }
        }
    },
}

实现props类型推导和默认值推导 myPropsHelper.ts

import { PropType } from "vue";

/**
 * vue.props类型推导
 */
export type GetPropsType<T> = {
    [key in keyof T]: T[key] extends { type: PropType<infer P> } ? P : never
}

/**
 * vue.props默认值推导
 * @param p : vue.props
 * @returns 有默认值的符合props类型的对象
 */
export const GetPropsDefault = (p: any) => {
    let _props: Record<string, any> = {}
    Object.keys(p).forEach((key: string) => {
        _props[key] = typeof p[key].default === 'function' ? p[key].default() : p[key].default
    });
    return _props as GetPropsType<typeof p>
}

使用

<template>
    <div>
        <my-component v-bind="case1" />
        <!-- 等价于 -->
        <my-component 
            :student-id="case1.studentId"
            :student-name="case1.studentName" 
            :address-info="case1.addressInfo"
        />
    </div>
</template>

<script lang="ts">
import { defineComponent, reactive } from 'vue'
import MyComponent from "./MyComponent.vue"
import props from '../props'
import { GetPropsType, GetPropsDefault } from './myPropsHelper'
export default defineComponent({
    components: {
        MyComponent,
    },
    setup() {
        type Props = GetPropsType<typeof props>
        const defaultProps = reactive<Props>(GetPropsDefault(props)) 
        return {
            case1: <Props>{
                ...defaultProps,
                studentName: '苏小胖'
            }
        }
    }
})
</script>