Skip to content

Conversation

@yoyo837
Copy link
Member

@yoyo837 yoyo837 commented Sep 29, 2025

Summary by CodeRabbit

  • 新特性
    • 无用户可见的新功能。
  • 重构
    • 若干高阶组件的公共返回类型与原组件类型保持一致,改进了 ref 与 props 的透传,减少不必要的类型断言,提升类型兼容性与调用一致性。
  • 文档
    • 无。
  • 其他
    • 移除多余的类型别名;上述签名变更可能需同步更新现有类型引用与调用处。

@yoyo837 yoyo837 changed the title chore: revert ts type changes and use smaller way. chore: revert ts type changes and use smaller way Sep 29, 2025
@coderabbitai
Copy link

coderabbitai bot commented Sep 29, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

src/Immutable.tsx 中移除 ImmutableProps 类型别名,将 makeImmutableresponseImmutable 的返回类型由 React.ComponentType<React.ComponentProps<T>> 改为直接返回泛型组件类型 T,并相应调整内部函数式组件实现、forwardRef/memo 组合与类型断言与 props/ref 传递方式。

Changes

Cohort / File(s) Summary
不可变组件包装调整
src/Immutable.tsx
- 移除类型 ImmutableProps<T extends React.ComponentType<any>> = Omit<React.ComponentProps<T>, 'ref'>
- makeImmutable<T extends React.ComponentType<any>>(Component: T, shouldTriggerRender?: CompareProps<T>): T(返回类型改为 T
- responseImmutable<T extends React.ComponentType<any>>(Component: T, propsAreEqual?: CompareProps<T>): T(返回类型改为 T
- 内部实现由以前的形式调整为函数表达式,简化 props 展开与 ref 处理的类型断言;保留 forwardRefmemo 组合但类型签名与返回值对齐

Sequence Diagram(s)

sequenceDiagram
  participant App as 使用处
  participant Wrapper as makeImmutable / responseImmutable
  participant Inner as 原始 Component

  rect #f0f7ff
    App->>Wrapper: 渲染 WrappedComponent(props, ref)
    note right of Wrapper #e8f2ff: forwardRef 封装\n(接收 ref 并传入 Inner)
    Wrapper->>Inner: 调用 Inner(props, ref)
    Inner-->>Wrapper: 返回 React 元素
    Wrapper-->>App: 返回 React 元素
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

我是一只小兔子,代码里跳躍,
签名轻轻回归本体,类型更清晰,
转发引用稳如草,memo 护着路,
一行一行改动,静听不可变的步履。 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed 标题以“chore: revert ts type changes and use smaller way”简洁地概括了此次提交的主要内容,即回退 TypeScript 类型修改并采用更精简的实现方式,能够让团队成员快速了解变更目的和范围。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ts-type-smaller

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a5add8e and fd65fbe.

📒 Files selected for processing (1)
  • src/Immutable.tsx (5 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @yoyo837, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on a chore-related task to refine and simplify the TypeScript definitions and usage within the src/Immutable.tsx file. The changes aim to improve the clarity and conciseness of the type system by removing an intermediate type, making function return types more specific, and eliminating redundant type assertions. This results in a more streamlined and robust codebase for handling immutable components.

Highlights

  • Type Simplification: The ImmutableProps type definition has been removed, streamlining the type declarations.
  • Improved Return Types: The return types for makeImmutable and responseImmutable functions have been refined from React.ComponentType<React.ComponentProps<T>> to a more precise T, enhancing type accuracy.
  • Reduced Type Assertions: Unnecessary as any type assertions have been eliminated, leading to cleaner and more type-safe code within the component logic.
  • Refactored Component Definitions: The ImmutableComponent definitions within makeImmutable and responseImmutable have been refactored from arrow functions to named functions.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@codecov
Copy link

codecov bot commented Sep 29, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (3a45618) to head (fd65fbe).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##            master       #51   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         4           
  Lines           91        90    -1     
  Branches        26        24    -2     
=========================================
- Hits            91        90    -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies the TypeScript types in Immutable.tsx by removing more specific types in favor of any and type assertions. While this makes the code shorter, it significantly reduces type safety for components using these HOCs. My review focuses on the implications of this trade-off, highlighting the loss of compile-time checks for props and inaccurate return type assertions. I've also pointed out a minor typo in a comment.

const refAble = supportRef(Component);

const ImmutableComponent = (props: ImmutableProps<T>, ref: React.Ref<any>) => {
const ImmutableComponent = function (props: any, ref: any) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using any for props and ref removes type safety for components wrapped with makeImmutable. The previous approach using a typed props object was more robust as it ensured that the props passed to the wrapped component were correctly typed. With any, we lose compile-time checks and editor support (like autocompletion and type hints) for props, which can lead to runtime errors. It would be highly beneficial to restore stronger typing here to protect consumers of this HOC.

return refAble
? (React.forwardRef(ImmutableComponent) as React.ComponentType<React.ComponentProps<T>>)
: (ImmutableComponent as unknown as React.ComponentType<React.ComponentProps<T>>);
return refAble ? React.forwardRef(ImmutableComponent) as unknown as T : (ImmutableComponent as T);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Casting the returned component to T is not type-safe. The HOC returns a new wrapper component, not the original component T. While the wrapper accepts the same props, it's a different component. This inaccurate typing can be misleading and might hide issues, for example if static properties of the original component are expected to be present on the wrapped component. The previous return type React.ComponentType<React.ComponentProps<T>> was more accurate and safer.

const refAble = supportRef(Component);

const ImmutableComponent = (props: ImmutableProps<T>, ref: React.Ref<any>) => {
const ImmutableComponent = function (props: any, ref: any) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similar to makeImmutable, using any here for props and ref in responseImmutable also removes type safety. This can make the components harder to use correctly and more prone to bugs. It's highly recommended to use specific types for props to provide a better developer experience for users of this function.

Comment on lines 96 to 98
return refAble
? (React.memo(React.forwardRef(ImmutableComponent), propsAreEqual) as React.ComponentType<
React.ComponentProps<T>
>)
: (React.memo(ImmutableComponent, propsAreEqual) as unknown as React.ComponentType<
React.ComponentProps<T>
>);
? React.memo(React.forwardRef(ImmutableComponent), propsAreEqual) as unknown as T
: (React.memo(ImmutableComponent, propsAreEqual) as unknown as T);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similar to makeImmutable, casting the memoized component to T is not type-safe. The returned component is a new wrapper component created by React.memo and React.forwardRef, not the original component T. This can lead to incorrect assumptions by the consumer of responseImmutable. A more accurate return type would better describe the returned component and avoid misleading the type system.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 670c7a8 and bc57cc9.

📒 Files selected for processing (1)
  • src/Immutable.tsx (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/Immutable.tsx (1)
src/index.ts (1)
  • useImmutableMark (14-14)

return refAble
? (React.forwardRef(ImmutableComponent) as React.ComponentType<React.ComponentProps<T>>)
: (ImmutableComponent as unknown as React.ComponentType<React.ComponentProps<T>>);
return refAble ? React.forwardRef(ImmutableComponent) as unknown as T : (ImmutableComponent as T);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

类型断言到 T 违背静态属性契约

这里把 React.forwardRef/React.memo 返回的新组件硬断言成原始的 T,但我们并没有把 Component 上的静态成员(自定义静态方法、defaultProps 扩展字段等)复制过去。结果是类型层面仍能访问这些静态属性,运行时却得到 undefined,一旦调用就会抛错。这是对外 API 的破坏。建议至少恢复之前返回 React.ComponentType<React.ComponentProps<T>> 的写法,或者引入 hoist-non-react-statics 之类的方案,在断言之前把静态成员完整同步过去,再返回 T。目前的实现必须修正后才能合并。

Also applies to: 97-98

@zombieJ
Copy link
Member

zombieJ commented Sep 30, 2025

@gemini-code-assist CR again

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

这个 PR 旨在简化 HOC 的类型定义,这是一个很好的目标。将返回类型从 React.ComponentType<React.ComponentProps<T>> 更改为 T 能够更好地保留原始组件的类型(包括静态属性),这是一个很大的改进。代码的重构,例如在 responseImmutable 中对 React.memo 的调用,也使代码更简洁。

然而,为了移除一些类型断言(as any),ImmutableComponentpropsref 被改成了 any 类型。这虽然达到了目的,但也牺牲了类型安全,是一种倒退。我建议使用更精确的类型,即使这意味着需要处理一些由此暴露出来的类型不匹配问题。我在代码中留下了具体的建议。

const refAble = supportRef(Component);

const ImmutableComponent = (props: ImmutableProps<T>, ref: React.Ref<any>) => {
const ImmutableComponent: React.ForwardRefRenderFunction<any, any> = (props, ref) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

ImmutableComponent 的类型定义为 React.ForwardRefRenderFunction<any, any> 会导致 propsref 失去类型信息,降低了类型安全性。虽然这可以避免在后续代码中使用 as any,但更好的做法是提供更精确的类型。

我建议使用 React.ElementRef<T>React.ComponentPropsWithoutRef<T> 来精确地定义 refprops 的类型。

请注意,这个改动可能会暴露出 shouldTriggerRender 函数的类型不匹配问题。它的类型 CompareProps<T> 期望的参数是 React.ComponentProps<T>,而 ImmutableComponentprops 类型是 React.ComponentPropsWithoutRef<T>。根本原因可能是 CompareProps<T> 的定义,它或许应该使用 React.ComponentPropsWithoutRef<T>。考虑到这是一个更深层次的问题,一个临时的解决方案可能是在调用 shouldTriggerRender 时进行类型断言,但这正是本次 PR 想要移除的。最好的方式是修复 CompareProps<T> 的类型定义。

Suggested change
const ImmutableComponent: React.ForwardRefRenderFunction<any, any> = (props, ref) => {
const ImmutableComponent: React.ForwardRefRenderFunction<
React.ElementRef<T>,
React.ComponentPropsWithoutRef<T>
> = (props, ref) => {

const refAble = supportRef(Component);

const ImmutableComponent = (props: ImmutableProps<T>, ref: React.Ref<any>) => {
const ImmutableComponent: React.ForwardRefRenderFunction<any, any> = (props, ref) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

makeImmutable 中的情况类似,这里使用 React.ForwardRefRenderFunction<any, any> 也导致了 propsref 的类型安全性的丧失。

建议使用更精确的类型来定义 ImmutableComponent

同样,请注意这个改动可能会影响 propsAreEqual 的类型检查。propsAreEqual 的类型是 CompareProps<T>,它期望的参数是 React.ComponentProps<T>。而 React.memo 会传入 ImmutableComponent 的 props,其类型是 React.ComponentPropsWithoutRef<T>,这会导致类型不匹配。这个问题也源于 CompareProps<T> 的定义。

Suggested change
const ImmutableComponent: React.ForwardRefRenderFunction<any, any> = (props, ref) => {
const ImmutableComponent: React.ForwardRefRenderFunction<
React.ElementRef<T>,
React.ComponentPropsWithoutRef<T>
> = (props, ref) => {

yoyo837 and others added 3 commits October 9, 2025 17:17
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@zombieJ zombieJ merged commit d172f3c into master Nov 3, 2025
10 checks passed
@yoyo837 yoyo837 deleted the ts-type-smaller branch November 3, 2025 03:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants