From c76c5a697b398e8e6db30e2abd04658277912a48 Mon Sep 17 00:00:00 2001 From: ryan Date: Sun, 16 Aug 2026 21:23:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=89=8D=E7=AB=AF=E6=98=BE=E5=BC=8F=20any=20?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 全前端显式 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 全绿 --- .../animate-ui/primitives/animate/slot.tsx | 29 ++++++++++++------- frontend/hooks/use-controlled-state.tsx | 3 +- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/frontend/components/animate-ui/primitives/animate/slot.tsx b/frontend/components/animate-ui/primitives/animate/slot.tsx index d52ee0a6..04ada8c8 100644 --- a/frontend/components/animate-ui/primitives/animate/slot.tsx +++ b/frontend/components/animate-ui/primitives/animate/slot.tsx @@ -1,7 +1,12 @@ 'use client'; 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'; type AnyProps = Record; @@ -16,8 +21,7 @@ type WithAsChild = | (Base & { asChild?: false | undefined }); type SlotProps = { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - children?: any; + children?: React.ReactNode | MotionValue | MotionValue; } & DOMMotionProps; function mergeRefs( @@ -63,21 +67,24 @@ function Slot({ ref, ...props }: SlotProps) { + const isValidChild = React.isValidElement(children); + const childrenType = isValidChild ? children.type : undefined; + const isAlreadyMotion = - typeof children.type === 'object' && - children.type !== null && - isMotionComponent(children.type); + isValidChild && + typeof childrenType === 'object' && + childrenType !== null && + isMotionComponent(childrenType); const Base = React.useMemo( () => isAlreadyMotion - ? (children.type as React.ElementType) - : motion.create(children.type as React.ElementType), - [isAlreadyMotion, children.type], + ? (childrenType as React.ElementType) + : motion.create(childrenType as React.ElementType), + [isAlreadyMotion, childrenType], ); - if (!React.isValidElement(children)) return null; - + if (!isValidChild) return null; const { ref: childRef, ...childProps } = children.props as AnyProps; const mergedProps = mergeProps(childProps, props); diff --git a/frontend/hooks/use-controlled-state.tsx b/frontend/hooks/use-controlled-state.tsx index 1b5eec23..b4ca8cfe 100644 --- a/frontend/hooks/use-controlled-state.tsx +++ b/frontend/hooks/use-controlled-state.tsx @@ -14,8 +14,7 @@ interface CommonControlledStateProps { * const [value, setValue] = useControlledState({ value: propValue, onChange: console.log }) * ``` */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function useControlledState( +export function useControlledState( props: CommonControlledStateProps & { onChange?: (value: T, ...args: Rest) => void; },