共计 3001 个字符,预计需要花费 8 分钟才能阅读完成。
最近在封装一个组件,应用的时候心愿父组件能给子组件传递一个泛型,在网上搜了半天,答案都是说要用 jsx 能力实现。具体写法如下:
应用 JSX
这段代码来自 Eluxjs 的示例我的项目 elux-vue-antd-admin,感兴趣的能够看下。
父组件:(为缩小篇幅,代码删了很多,当伪代码看吧)
const Component = defineComponent<Props>({props: ['listPathname', 'mergeColumns'] as any,
setup(props) {return () => {
return (
<MTable<ListItem> // 这里应用子组件 MTable,传递泛型 ListItem
size={tableSize}
commonActions={commonActions}
selection={selection}
loading={listLoading === 'Start' || listLoading === 'Depth'}
/>
);
};
},
});
export default Component;
子组件:(子组件比拟麻烦)
interface Props<T = Record<string, any>> extends TableProps<T> {
class?: string;
columns: MColumns<T>[];
selectedRows?: Partial<T>[];
selection?: MSelection<T>;
}
const Component = defineComponent<Props>({
name: styles.root,
props: [
'class',
'columns'
] as any,
setup(props: Props) {return () => {const {class: className = '', dataSource, onChange, rowKey ='id', loading, size, bordered, locale, scroll} = props;
return (<div class={styles.root + ' ' + className}>
{headArea.value}
<Table
columns={columnList.value}
rowSelection={rowSelection.value}
onChange={onChange}
size={size}
/>
</div>
);
};
},
}) as any;
export default Component as <T>(props: Props<T>) => JSX.Element;
这里应用 Component as <T>(props: Props<T>) => JSX.Element;
来做到接管泛型,但生产它的父组件必须用 jsx。
因为我的项目不不便用 jsx,我找了很久如何用 template 来传递泛型,终于找到了!
应用 Template
先看子组件:
<script
lang="ts"
setup
// 要害:setup script 有个 generic 属性,能够申明泛型,供组件应用
generic="T extends {name: string; age: number;}, Q extends {title:string}"
>
// 在 props 中应用泛型,rowKey 应用 keyof T,plainObj 应用第二个泛型 Q
defineProps<{personList: T[];
rowKey: keyof T;
plainObj: Q;
}>();
</script>
<template>
<div>
// 模板中失常应用 props
<h3 v-for="item in personList" :key="item.name">
{{item.age}}
</h3>
// 用插槽向父组件裸露数据,plainObj 的类型是 Q
<slot :obj="plainObj" />
</div>
</template>
generic 属性的作用就是给组件中应用的泛型提供一个“起源”,这样父组件生产子组件的时候,只有给 personList 传递一个数据,泛型 T 就会被主动推断进去。
generic 属性的泛型能够抉择 extends 一些已知的属性,因为子组件本身应用到 props 的哪些属性,和生产该组件的中央是无关的。
父组件:
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue';
// 给 list 的 item 申明类型,该类型能够是子组件 T 的超集
interface DataType {
name: string;
age: number;
gender: 'male' | 'female' | 'wallmart bag';
hobby?: 'jk' | 'dk' | '敌法师';
}
const list: DataType[] = [
{
name: 'ming',
age: 20,
gender: 'male',
hobby: '敌法师'
},
{
name: 'hong',
age: 20,
gender: 'female'
},
{
name: 'hua',
age: 20,
gender: 'wallmart bag'
}
];
</script>
<template>
<div>
<HelloWorld
:person-list="list"
row-key="genderr"
:plainObj="{happy: true, title:' 低头 '}"
v-slot="{obj}"
>
<!-- 👆 不能将类型“"agg"”调配给类型“keyof T”。-->
{{obj.happ}}
<!-- 👆 属性“happ”在类型“{happy: boolean; title: string;}”上不存在。你是否指的是“happy”? -->
</HelloWorld>
</div>
</template>
<style></style>
能够看到,子组件推断出了 T 的类型是 DataType,报错 类型 "genderr" 不可调配给类型“keyof T”。你的意思是 "gender"?
。
Q 也胜利的推断了进去,报错 属性“happ”在类型“{happy: boolean; title: string;}”上不存在
,这里的 {happy: boolean; title: string;}
即是咱们传给 plainObj
属性的泛型 Q
这样就实现了 父组件通过 props,给子组件传递所需的泛型。
generic 属性的泛型如何 extends 一些内部的类型,或者 extends 已有的接口呢?
额定应用一个 script 标签即可
<script>
// 额定应用一个 script 标签即可
import {SecendType} from "./index";
interface FirstType {
name: string;
age: number;
}
</script>
<script lang="ts" setup generic="T extends FirstType, Q extends SecendType">
defineProps<{personList: T[];
rowKey: keyof T;
plainObj: Q;
}>();
</script>
<template>
<div>
<h3 v-for="item in personList" :key="item.name">
{{item.age}}
</h3>
<slot :obj="plainObj" />
</div>
</template>