type QQQ = {
a?: never;
b: string;
c: string;
};
type WWW = {
a: string;
b: string;
d: string;
};
type ForwardedRefWithOverride<T extends [object, HTMLElement]> = UnionToIntersection<
T extends T ? ForwardRefExoticComponent<PropsWithoutRef<T[0]> & RefAttributes<T[1]>> : never
>;
const forwardRefWithOverrides = <T extends [object, HTMLElement][]>(
render: ForwardRefRenderFunction<T[number][1], T[number][0]>,
) => {
return forwardRef(render) as ForwardedRefWithOverride<T[number]>;
};
export const Ccc = forwardRefWithOverrides<[[QQQ, HTMLButtonElement], [WWW, HTMLLinkElement]]>((props, ref) => {
if (typeof props.a === 'string') {
const { a, b, d } = props;
return (
<>
<link ref={ref as ForwardedRef<HTMLLinkElement>} />
{a}
{b}
{d}
</>
);
}
{
const { a, b, c } = props;
return (
<button ref={ref as ForwardedRef<HTMLButtonElement>} type="button">
{a}
{b}
{c}
</button>
);
}
});
Ccc.displayName = 'Ccc';
export const Vvv = () => {
const ref1 = useRef<HTMLButtonElement>(null);
const ref2 = useRef<HTMLLinkElement>(null);
return (
<>
<Ccc ref={ref1} b="asd" c="asd" />
<Ccc ref={ref2} a="asd" b="asd" d="asd" />
{/* @ts-expect-error - c missed */}
<Ccc b="asd" d="asd" />
{/* @ts-expect-error - d missed, extra c */}
<Ccc a="asd" b="asd" c="asd" />
{/* @ts-expect-error - extra c */}
<Ccc a="asd" b="asd" c="asd" d="asd" />
{/* @ts-expect-error - wrong ref */}
<Ccc ref={ref2} b="asd" c="asd" />
</>
);
};
можешь в принципе свободно без документации получать на ее основе исходный продукт/приложение и т.д .
А сам подход без использования useState называется uncontrolled components и он достаточно часто используется
основное отличие в данном случае будет в том, что изменение значения в инпуте таким образом не вызывает нового рендера
я пытаюсь добиться результата в будущем, чтобы я или мои коллеги, при попытке нажатия по компоненте + ctrl проваливались в ts файл с типами.