前端显式 any 类型清理

全前端显式 any 计数 2→0:Slot children?: any → ReactNode | MotionValue 联合(motion 真实类型),顺带修复潜在崩溃(原代码在 isValidElement 前访问 children.type,children 缺失时 TypeError,现无效 children 返回 null,hooks 无条件合规);useControlledState Rest extends any[] → unknown[]。两处 eslint-disable no-explicit-any 注释随之删除。

Experiments: #28
Metric: 全前端 any 2 → 0,tsc/eslint/vitest 全绿
This commit is contained in:
ryan
2026-08-16 21:23:38 +08:00
parent 5a8722ff07
commit c76c5a697b
2 changed files with 19 additions and 13 deletions
@@ -1,7 +1,12 @@
'use client'; 'use client';
import * as React from 'react'; import * as React from 'react';
import { type HTMLMotionProps, isMotionComponent, motion } from 'motion/react'; import {
type HTMLMotionProps,
type MotionValue,
isMotionComponent,
motion,
} from 'motion/react';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
type AnyProps = Record<string, unknown>; type AnyProps = Record<string, unknown>;
@@ -16,8 +21,7 @@ type WithAsChild<Base extends object> =
| (Base & { asChild?: false | undefined }); | (Base & { asChild?: false | undefined });
type SlotProps<T extends HTMLElement = HTMLElement> = { type SlotProps<T extends HTMLElement = HTMLElement> = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any children?: React.ReactNode | MotionValue<string> | MotionValue<number>;
children?: any;
} & DOMMotionProps<T>; } & DOMMotionProps<T>;
function mergeRefs<T>( function mergeRefs<T>(
@@ -63,21 +67,24 @@ function Slot<T extends HTMLElement = HTMLElement>({
ref, ref,
...props ...props
}: SlotProps<T>) { }: SlotProps<T>) {
const isValidChild = React.isValidElement(children);
const childrenType = isValidChild ? children.type : undefined;
const isAlreadyMotion = const isAlreadyMotion =
typeof children.type === 'object' && isValidChild &&
children.type !== null && typeof childrenType === 'object' &&
isMotionComponent(children.type); childrenType !== null &&
isMotionComponent(childrenType);
const Base = React.useMemo( const Base = React.useMemo(
() => () =>
isAlreadyMotion isAlreadyMotion
? (children.type as React.ElementType) ? (childrenType as React.ElementType)
: motion.create(children.type as React.ElementType), : motion.create(childrenType as React.ElementType),
[isAlreadyMotion, children.type], [isAlreadyMotion, childrenType],
); );
if (!React.isValidElement(children)) return null; if (!isValidChild) return null;
const { ref: childRef, ...childProps } = children.props as AnyProps; const { ref: childRef, ...childProps } = children.props as AnyProps;
const mergedProps = mergeProps(childProps, props); const mergedProps = mergeProps(childProps, props);
+1 -2
View File
@@ -14,8 +14,7 @@ interface CommonControlledStateProps<T> {
* const [value, setValue] = useControlledState({ value: propValue, onChange: console.log }) * const [value, setValue] = useControlledState({ value: propValue, onChange: console.log })
* ``` * ```
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any export function useControlledState<T, Rest extends unknown[] = []>(
export function useControlledState<T, Rest extends any[] = []>(
props: CommonControlledStateProps<T> & { props: CommonControlledStateProps<T> & {
onChange?: (value: T, ...args: Rest) => void; onChange?: (value: T, ...args: Rest) => void;
}, },