背景
为了实现函数组件的参数类型能够被其他的某个参数传入的具体值控制的功能,需要用重载的方式来定义组件
重载箭头函数
函数组件首先是一个箭头函数,因此需要先能够重载箭头函数
在typescript中可以用 Call Signatures
方式来重载一个箭头函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| interface ArrowFunc { <T>(x: T): T;
<T>(x: T[]): T[]; }
const arrowFunc1: ArrowFunc = <T>(x: T): T => { if (Array.isArray(x)) { return x.map((item) => item) as T } else { return x; } };
const arrowFunc2: ArrowFunc = (x) => { if (Array.isArray(x)) { return x.map((item) => item); } else { return x; } }
function arrowFuncOverload(x: number): number; function arrowFuncOverload(x: string): string; function arrowFuncOverload(x: any): any { if (typeof x === "number") { return x + 1; } else { return x + "!"; } }
const a = arrowFunc1(10); const b = arrowFunc1(["hello", "world"]);
console.log(arrowFuncOverload(10)); console.log(arrowFuncOverload("hello"))
|
重载React函数组件
在上面的例子中,我们定义了一个名为 ArrowFunc
的接口,它包含两个重载函数。我们还定义了一个名为 arrowFuncOverload
的函数,它使用重载来支持不同类型的参数。
但是在 React
的函数组件中,因为返回值均为JSX.Element
,需要重载的场景通常为 需要根据传入的某个参数来限定其他参数的传入类型的场景,此时的实现方式应当为:
jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| interface FuncComponentProps<R extends boolean> { trigger: R, changedParams: R extends true ? number : string }
interface FuncComponent { <T>(props: FuncComponentProps<true>): JSX.Element;
<T>(props: FuncComponentProps<false>): JSX.Element; }
const FuncComponent1: FuncComponent = <R extends boolean>(props: FuncComponentProps<R>) => {
const {trigger, changedParams} = props
let showX: R
showX = trigger
let text = ''
if (trigger) { text = (changedParams as number).toString() } else { text = changedParams as string }
return <div>{text} < /div> };
const FuncComponent2: FuncComponent = (props) => {
const {trigger, changedParams} = props
let text = ''
if (trigger) { text = (changedParams as number).toString() } else { text = changedParams as string }
return <div>{text} < /div> };
const ShowFuncComponent = () => {
return <div> <FuncComponent1 trigger={true} // trigger=true, changedParams只接受number // changedParams={'1'} // 会报错 changedParams={1} /> <FuncComponent1 trigger={false} // trigger=false, changedParams只接受string // changedParams={1} // 会报错 changedParams={'1'} /> </div> }
|
⚠️ 需要注意的是,重载使得调用方可以明确知晓自己传入不同参数时受影响的参数的类型,但组件内部是无从得知的,如果类型变化,需要编写者自己显式指定什么条件下会变化类型的参数是什么类型
上面的例子中,我们以trigger参数作为触发changedParams参数类型变化的触发器,实现了外部传入不同的参数值时被控制的参数的要求类型不同的功能,该写法可以实现包括但不限于以下需求:
- 根据传入是否必填参数修改onChange的参数是否可以为空
- 根据传入的类型参数限定传入的详细数据参数的结构类型
参考