ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Ant Design 工具类型实战:GetRef、GetProps 与 GetProp 的用法与源码原理

Ant Design 工具类型实战:GetRef、GetProps 与 GetProp 的用法与源码原理 Ant Design 工具类型实战GetRef、GetProps 与 GetProp 的用法与源码原理【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-designAnt Design 自5.13.0版本起提供了一组纯类型层面的工具——GetRef、GetProps与GetProp用于从组件、Context 或 props 接口中精确提取类型定义。本文以 Ant Design 官方文档Util为骨架结合仓库中 type.ts 的完整实现、type.test.tsx 测试用例以及组件内部的真实调用示例讲清这三个类型的适用场景、取值规则与底层原理帮助你在业务代码中编写类型安全且无需手动维护的ref、props、回调类型。一、它们解决什么问题在 React TypeScript 项目中经常会遇到以下需求给Select、DatePicker这类复杂组件的ref标注类型例如调用ref.current.focus()但BaseSelectRef等内部类型未必每个都单独导出从Checkbox.Group这类「组件的静态属性」上提取 props 类型避免复制一份CheckboxGroupProps拿到SelectProps中单个属性如options、onChange的类型尤其是「对象或函数」这种联合类型属性想直接拿到其函数分支的返回值。Ant Design 的答案就是这组工具类型它们全部定义在 components/_util/type.ts 中并通过包入口 components/index.ts 统一导出// components/index.ts export type { GetProp, GetProps, GetRef } from ./_util/type;因此使用方式就是从antd包中按import type导入零运行时开销。二、GetRef提取组件的 ref 类型官方文档对GetRef的定位是获取组件的ref属性定义对「未直接暴露Ref类型的组件」或「需要透传给子组件的 ref」非常有用。import { Select } from antd; import type { GetRef } from antd; type SelectRefType GetReftypeof Select; // BaseSelectRef注意第二个参数传的是typeof Select组件构造器类型而不是组件实例。典型用法const ref React.useRefGetReftypeof Select(null); // ref.current?.focus()、ref.current?.blur() 等均获得完整的类型提示从源码结构看GetRef的实现分为三步type.tstype ReactRefComponentProps extends { ref?: React.Refany | string } ( props: Props, ) React.ReactNode; type ExtractRefAttributesRefT T extends React.RefAttributesinfer P ? P : never; export type GetRefT extends ReactRefComponentany | React.Componentany T extends React.Componentany ? T // 类组件ref 指向类实例本身 : T extends React.ComponentTypeinfer P ? ExtractRefAttributesRefP // 函数组件从 props 中抽出 RefAttributesRef : never;其逻辑可以拆解为类组件分支T extends React.Componentany ? T : ...类组件的 ref 天然就是类实例本身直接透传函数组件分支React.forwardRefT, Props展开后的 props 形状是Props React.RefAttributesT其中RefAttributesinfer P携带的P就是useImperativeHandle暴露的类型。ExtractRefAttributesRef正是靠条件类型infer把它抠出来兜底两者都不满足时返回never在类型层面显式暴露问题。测试用例 type.test.tsx 覆盖了这三条路径类组件CC、forwardRef函数组件RefFC以及React.ForwardRefExoticComponentInnerProps React.RefAttributesInnerRef这种直接书写 exotic 类型的场景验证了GetRef对RefAttributes的提取是稳定可靠的。三、GetProps提取组件或 Context 的 props 类型GetProps获取组件的props属性定义import { Checkbox } from antd; import type { GetProps } from antd; type CheckboxGroupType GetPropstypeof Checkbox.Group;Checkbox.Group是Checkbox上的静态属性typeof Checkbox.Group得到它的组件类型GetProps再从中推导 props从而拿到与CheckboxGroupProps完全等价、但无需依赖该类型是否被导出的结果。也支持 React.Context这是GetProps相对React.ComponentProps的独有能力——直接提取 Context 的 value 类型import type { GetProps } from antd; interface InternalContextProps { name: string; } const Context React.createContextInternalContextProps({ name: Ant Design }); type ContextType GetPropstypeof Context; // InternalContextProps与React.ComponentProps的区别能力React.ComponentPropsGetProps原生标签名如button支持不支持React 组件函数/类/forwardRef支持支持React.Context的 value 类型不支持支持透传一个已有的 props 类型对象会尝试按组件解析原样透传对照 type.ts 的实现四个分支一目了然export type GetPropsT extends React.ComponentTypeany | object T extends React.Contextinfer CP ? CP // 1. Context抽出 value 泛型 : T extends React.ComponentTypeinfer P ? P // 2. React 组件抽出 props 泛型 : T extends object ? T // 3. 普通对象类型原样透传 : never;第 3 个分支解释了为什么GetProp的文档示例里可以同时写GetPropSelectProps, options直接传接口和GetProptypeof Select, options传组件——两种入参都能被GetProps归一成同一份 props 类型。四、GetProp提取单个属性类型含 Return 分支GetProp用于获取组件的单个props或context属性定义。它内部封装了NonNullable所以「属性可选」时你不必再手动处理| undefinedimport { Select } from antd; import type { GetProp, SelectProps } from antd; // 以下两种都可以生效 type SelectOptionType1 GetPropSelectProps, options[number]; type SelectOptionType2 GetProptypeof Select, options[number]; type ContextOptionType GetProptypeof Context, name;第三个参数Return拿函数属性的返回值Ant Design 5.x 起大量语义化属性采用「对象或函数」的联合类型如classNames、styles此时最常用的是通过第三个参数Return提取函数分支的返回值import type { GetProp } from antd; interface Props { func?: (value: number) string; configOrFunc?: { configA?: string } | (() { anotherB?: string }); } type OnChangeReturn GetPropProps, func, Return; // string type ClassNamesReturn GetPropProps, configOrFunc, Return; // { anotherB?: string }实现上type.tsexport type GetProp T extends React.ComponentTypeany | object, PropName extends keyof GetPropsT, Type extends Default | Return Default, Type extends Default ? NonNullableGetPropsT[PropName] : Type extends Return ? ReturnTypeExtractGetPropT, PropName, Default, (...args: any[]) unknown : never;关键点在于Extract..., (...args: any[]) unknown对于「对象 | 函数」的联合类型Extract只保留函数分支再由ReturnType取出返回值。如果属性只有对象分支没有函数形态Extract的结果不是函数类型ReturnType会得到unknown语义上的空值——所以Return仅应对「存在函数形态」的联合属性使用。五、仓库内的真实用法语义化样式函数这三个类型并非纸面工具Ant Design 自身的 demo 就在用。以 Button 的 style-class 示例 为例styles属性的完整形态是「对象或 (info) 对象」import type { ButtonProps, GetProp } from antd; // 函数形态的 styles返回类型直接由 GetProp 推导 const stylesFn: ButtonProps[styles] (info): GetPropButtonProps, styles, Return { if (info.props.type primary) { return { root: { backgroundColor: #171717 }, content: { color: #fff }, }; } return {}; };同样的模式还出现在 Alert、Anchor、Badge、Card、Cascader、Checkbox、Collapse、ColorPicker 等组件的demo/style-class.tsx与__tests__/semantic.test.tsx中——从源码结构看这是 Ant Design 为「对象或函数」型语义化属性统一推荐的用户侧标注方式可以推断它将成为后续新组件文档的惯例写法。六、测试如何验证这三个类型type.test.tsx 用「类型标注 运行时断言」的方式锁定了行为边界GetProps分别对函数组件FC、类组件CC、forwardRef组件RefFC提取 props确认const props: Props { bamboo: 123 }可通过编译见 第 26-49 行GetRef类组件、forwardRef组件、ForwardRefExoticComponent三种写法都能得到正确的 ref 类型见 第 51-81 行GetProp可选属性自动去undefinedoptional用例、直接传接口interface directly用例、以及classNames联合类型下的Return提取Type is return用例均被覆盖见 第 83-111 行。由于 TypeScript 的类型检查发生在编译期这类测试的价值在于把「类型推断结果」固化进 CI一旦上游GetRef/GetProps/GetProp的实现被改动导致推断退化测试会直接编译失败。七、选择建议与参考结合 官方文档 与源码实际开发中的选择策略是标注 ref 类型优先GetReftypeof Component组件未导出XxxRef时尤其有用取组件/Context 的 props用GetProps特别是typeof Xxx.Group这类静态属性组件和自定义 Context取单个属性用GetProp遇到「对象 | 函数」联合属性再加Return原生 DOM 标签仍使用React.ComponentPropsbutton等官方类型GetProps不支持标签名字符串。类型入参返回值定义位置GetRefT组件构造器类型类组件为T本身函数组件为RefAttributes中提取的 ref 类型type.ts#L84-L89GetPropsT组件类型 /React.Context/ 普通对象类型props 泛型 / Context value 泛型 / 原样透传type.ts#L29-L36GetPropT, K, Type?组件或 props 类型 属性名 可选Default \| ReturnNonNullable后的属性类型或函数分支的返回值type.ts#L57-L65以上类型自5.13.0引入在当前仓库antd6.6.2见 package.json中持续被内部示例与测试依赖属于可放心用于业务代码的稳定公开 API。【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-design创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表