Comments (9)
This is tricky. By default this is done with a variance-based short circuiting; not doing this would be catastrophic to performance. Since it's only needed to probe the type deeper if it's the case that T
is only referenced in places where it's unioned with null
, a better workaround would be to do something like this
type RefObject<T> = _RefObject<Exclude<T, null>>;
interface _RefObject<T> {
current: T | null
}
from typescript.
Ah interesting. I figured it was for performance. I guess your workaround would need to be added to the old versions of the React types (e.g. 18, 17, 16, etc), since React 19 removed the | null
. Not sure if they'd be open to that and it would require everyone update to a new patch.
The other alternative we were considering for our library was to have our own copy of RefObject
locally and use that everywhere instead of the one imported from react
. That should also work but it means that each library that wants to maintain compatibility with multiple React versions will need to do that.
from typescript.
Not sure if they'd be open to that and it would require everyone update to a new patch.
If it's not breaking, you can file a PR and we see if it integrates cleanly.
type RefObject<T> = _RefObject<Exclude<T, null>>;
interface _RefObject<T> {
current: T | null
}
This is just really gnarly and given how unpredictable type emission is in TypeScript is with numerous issues closed as intended or left unaddressed, I'd want to consider first if we want to merge this. There are already enough types to deal with as learners and adding some weird _
prefixed types just makes it worse if they leak into user code.
from typescript.
Yeah... maybe ok if it was an internal type but still not ideal that projects would need to upgrade the 16/17/18 types in order to fix compatibility with libraries built for the 19 types either.
Would your recommendation for libraries that need to support multiple React versions be to make their own copy of RefObject
like we're thinking of doing in React Aria? adobe/react-spectrum#6632
from typescript.
not ideal that projects would need to upgrade the 16/17/18 types in order to fix compatibility with libraries built for the 19 types either.
I don't think this is an issue. I think if we can't even recommend updating libraries by a patch version, we've lost the ability to move the ecosystem forward. We can recommend upgrading React types by a patch once, or teach each library how to add a compat layer and then rely on consumers to upgrade each of these libraries? Seems way more simple to fix this in React types.
But if it requires this workaround that may leak into emitted types, it doesn't seem like a good workaround. Regardless of whether we do this in React types or 3rd party libraries. It would be more helpful if TypeScript would either fix this or improve type emission so that libraries are in control of what types are public and private.
Why can't you upgrade all your callsites of RefObject
to use RefObject<T | null>
right now ignoring anything that comes in React 19? You said it causes errors but I'm not seeing any in the playground nor do I see an explainer why it should error. The sample code you posted could be fixed if all RefObject
usages would use RefObject<T | null>
.
from typescript.
Why can't you upgrade all your callsites of RefObject to use RefObject<T | null> right now
Yeah that's what we've done. The problem occurs when passing a ref typed as RefObject<T | null>
to anything that accepts React.RefAttributes<T>
in previous versions of React, including builtin JSX elements like <div>
, and any forwardRef
components.
Here's a more practical example of what I mean: Playground
In React 19, ForwardedRef
and RefAttributes
include RefObject<T | null>
but in previous versions of React, the | null
is inside the definition of RefObject
. So due to this TS limitation, if we add T | null
to our definition, we are compatible with React 19 but not 18 or previous, and if we don't add it we are compatible with previous but not 19.
from typescript.
That is a problem that I would love being able to fix in React types. But this _RefObject
types appears in emitted declarations and we just created another problem that'll take years to get rid of when TypeScript changes behavior in that area. And there's the cost of having to learn/teach why we have this intermediate type as well.
from typescript.
Yeah I agree. Ideally TS would fix this issue and prioritize correctness over performance. But in the meantime we'll need a recommendation because I would imagine we are not the only library that will be affected by this.
Another option I thought of would be to add a new NullableRefObject
type in both old and new versions of the React types. In old react it could be an alias:
// In old react types
type NullableRefObject<T> = RefObject<T>;
and in React 19 it could add null
to T:
// In React 19
type NullableRefObject<T> = RefObject<T | null>;
Then libraries could use NullableRefObject
everywhere. Perhaps slightly less hacky but still requires updating many versions of the types, and teaching a new type. 🤔
from typescript.
I'm not endorsing this as a great solution, but it works to get structural comparison as a fallback (thus preserving the perf benefits of variance measurement)
declare const UnreliableSymbol: unique symbol;
type Struct<T> = `${T & string}`;
type DataOrNull< /* unreliable out */ T> = {
data: T | null;
[UnreliableSymbol]: Struct<T>;
}
declare function check(s: DataOrNull<string>): void;
declare let foo: DataOrNull<string | null>;
check(foo); // ok
from typescript.
Related Issues (20)
- [Regression] Circular reference error when passing a class expression with non-primitive static properties to a generic function
- [NewErrors] 5.6.0-dev.20240714 vs 5.5.3 HOT 9
- [ServerErrors][JavaScript] 5.6.0-dev.20240714 vs 5.5.3 HOT 13
- [ServerErrors][TypeScript] 5.6.0-dev.20240714 vs 5.5.3 HOT 21
- spread operator infer to wrong type with method override and generic HOT 6
- Intellisense is slow and some things don't work HOT 7
- Constructor cannot access own protected instance when typed as union HOT 3
- This comparison appears to be unintentional because the types 'U[K]' and 'T[K]' have no overlap.ts(2367) HOT 3
- [isolatedDeclarations] Optional parameter in arrow function typed as imported generic type gets emitted as `any` HOT 2
- Easier use of indexed access types on nullable/optional types HOT 2
- Narrow conditional type HOT 2
- Error for path not found when ended with asterisk
- `tryGetPerformanceHooks` throws on Stackblitz with ts 5.5.3 HOT 3
- Avoid providing promise methods as completions at return positions in non-async functions
- Consider disallowing `in` operator use with arbitrary key operands on closed types for which the keys are known HOT 2
- Convert to ESM uses template strings instead of string literals HOT 1
- Running type checker produces js out of memory error HOT 2
- Callback argument type not inferred for union of interfaces HOT 1
- Como Hackear Instagram 2024 Hackear Instagram Metodos Atualizados #221857
- [transpileDeclaration API] ts.transpileDeclaration always returns empty sourceMapText
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from typescript.