@types/react 包中获取 ComponentProps 有几个工具类型(Utility Type) 可以使用
ComponentProps v.s ComponentPropsWithRef v.s ComponentPropsWithoutRef, 本文介绍了该如何选择这三个工具类型.
TLDR | 长话短说
现代 React 应用, 只使用 Function Component 的情况下: 可以忘掉 ComponentPropsWithRef, 不需要 ref 时使用 ComponentPropsWithoutRef, 其他情况使用 ComponentProps.
包版本
本文以 react@19 & @types/react@19 进行说明
定义摘抄
node_modules/.pnpm/@types+react@19.2.9/node_modules/@types/react/index.d.ts
type PropsWithoutRef<Props> =
// Omit would not be sufficient for this. We'd like to avoid unnecessary mapping and need a distributive conditional to support unions.
// see: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
// https://github.com/Microsoft/TypeScript/issues/28339
Props extends any ? ('ref' extends keyof Props ? Omit<Props, 'ref'> : Props) : Props
type JSXElementConstructor<P> =
| ((props: P) => ReactNode | Promise<ReactNode>)
// constructor signature must match React.Component
| (new (props: P, context: any) => Component<any, any>)
// --------------------------------
type ComponentProps<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> =
T extends JSXElementConstructor<infer Props>
? Props
: T extends keyof JSX.IntrinsicElements
? JSX.IntrinsicElements[T]
: {}
type ComponentPropsWithRef<T extends ElementType> =
T extends JSXElementConstructor<infer Props>
? // If it's a class i.e. newable we're dealing with a class component
T extends abstract new (args: any) => any
? PropsWithoutRef<Props> & RefAttributes<InstanceType<T>>
: Props
: ComponentProps<T>
type ComponentPropsWithoutRef<T extends ElementType> = PropsWithoutRef<ComponentProps<T>>;
从实现上看
ComponentProps是从JSXElementConstructor上 infer function-signature or class-signatureComponentPropsWithoutRef是从ComponentProps+ 类似 omit 逻辑.ComponentPropsWithRef对 class component 有特殊照顾.
从实例看
IntrinsicElement
ComponentProps<'div'>=>React.JSX.IntrinsicElements['div']ComponentPropsWithRef<'div'>与ComponentProps<'div'>完全一致
FunctionComponent
function Greeting({name}: {name: string}) {
return <div>Hello, {name}</div>
}
ComponentProps<Greeting>=>Parameters<typeof Greeting>[0]ComponentPropsWithRef<Greeting>与ComponentProps<Greeting>完全一致
class component
ComponentProps<ClassComponent>获取 Props 类型ComponentPropsWithRef<ClassComponent>=>PropsWithoutRef<ComponentProps<ClassComponent>> & RefAttributes<InstanceType<T>
结论
如果只使用 function component + intrinsic elements 的情况下
ComponentPropsWithRef与ComponentProps完全一致.- 可以忘掉
ComponentPropsWithRef: 不需要 ref 时使用ComponentPropsWithoutRef, 其他情况使用ComponentProps