Fixes #35572, and the problem that using useRef with ref={} currently yields error#38228
Conversation
… <div ref={a}> currently yields error
|
@staeke Thank you for submitting this PR! 🔔 @johnnyreilly @bbenezech @pzavolinsky @digiguru @ericanderson @DovydasNavickas @theruther4d @guilhermehubner @ferdaber @jrakotoharisoa @pascaloliv @Hotell @franklixuefei @Jessidhia @saranshkataria @lukyth @eps1lon - please review this PR in the next few days. Be sure to explicitly select If no reviewer appears after a week, a DefinitelyTyped maintainer will review the PR instead. |
eps1lon
left a comment
There was a problem hiding this comment.
My issue with this change is that the overloaded ref type is only encountered before the ref is initialized. With this change the "type lifecycle" becomes undefined - HTMLDivElement - null (- HTMLDivElement - null)*. Since most of the use cases will not special case the very first cycle (undefined) I think it's fine to require explicit type annotation (HTMLDivElement | undefined) if you're interested in it or require const divRef = useRef<HTMLDivElement>(null).
As it stands right now this would be a breaking change if previous code strictly compared to null (current === null) since this would only narrow down to HTMLDivElement | undefined.
|
@staeke One or more reviewers has requested changes. Please address their comments. I'll be back once they sign off or you've pushed new commits or comments. Thank you! |
|
Thanks for reviewing @eps1lon . I agree and disagree. Since the change is potentially breaking I agree we should be bumping the major. I don't think status quo is acceptable though. But I do think we can reach a compromise that provides reasonable results for all use cases 1.First, and to the point with this PR - I don't think it's acceptable to require actual code changes from users (as opposed to typing changes) to accommodate ts issues - I'm thinking about adding a const ref = useRef<HTMLDivElement|undefined>()
return <div ref={ref}/>...yields an error, so I don't see how your proposed solution works. Also, I personally think it's dirty to require But, I'm all fine with changing interface RefAttributes<T> extends Attributes {
ref?: Ref<T | undefined>;
}
interface ClassAttributes<T> extends Attributes {
ref?: LegacyRef<T | undefined>;
}Would you be ok with that? 2.Secondly, I don't think it's acceptable to see that a textbook example yields a typescript error, and one that is also not correct. I'm thinking about: const ref = useRef()
return <div ref={ref}/>I think this use case is best solved by having useRef default its type parameter to 3.Third, I think the |
|
I have yet another problem with not including const n = useRef<number>()
n.current.toFixed()Currently yields no ts error. Breaks at runtime though Now that could be fixed by amending function useRef<T>(): MutableRefObject<T|undefined>;And, to be clear, and summarize it all, this would my preferred overloads: function useRef<T = any>(): MutableRefObject<T|undefined>;
function useRef<T>(initialValue: T|null): MutableRefObject<T; |
|
There is a reason why the overloads are like they are. Maybe I need to write a lot more comments in the First, As for the overloads, here are the current ones: function useRef<T>(initialValue: T): MutableRefObject<T>;
function useRef<T>(initialValue: T|null): RefObject<T>;
function useRef<T = undefined>(): MutableRefObject<T | undefined>;The first overload is what you should hit whenever your initial value is sufficient to infer the generic, or when it is directly compatible with the explicit generic. This is what will happen with, for example, The second overload is the convenience overload when you want something be passed as a The third overload is there when you give no arguments (i.e. the "first argument" is As I said in all cases, unless you want to use the |
|
@Jessidhia So how does one create a ref object, with a generic argument, an initial value of null, and have TS complain when there's improper usage? I'd expect a TS error in this: const ref = useRef<string>(null)
console.log(ref.current.toUpperCase())But it happily compiles: https://codesandbox.io/s/sparkling-firefly-e6fjk |
codesandbox has likely |
|
|
Fixes #35572, and the problem that using
currently yields error
Please fill in this template.
npm test.)npm run lint package-name(ortscif notslint.jsonis present).Select one of these and delete the others:
If changing an existing definition: