-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Recursive Mapped Type Narrows Branded Property to Never #35992
Comments
The produced output is correct. Effectively you've written a type that produces a You could consider reversing the conditional: export type PreloadedState<S> = {
[K in keyof S]: S[K] extends (string | number | boolean) ? S[K] : PreloadedState<S[K]>;
};
export type Branded<K, T> = T & {
__BRAND__: K;
};
type InitialState = PreloadedState<{
someString: Branded<'Foo', string>;
}>; but ultimately |
@RyanCavanaugh thanks for the response! Reversing the conditional seems like a good solution, as well as updating consumers to accept I am curious to know a couple things...
|
It won't resolve to |
@AnyhowStep I see. Is there a general rule about when resolution to |
Ummmmm........ Not as far as I know. But in 3.7.2, it is immediately reduced to However, |
Branding a primitive with an object type is an at-your-own-risk endeavor. Basically you can do this as long as the type never goes through a simplifying transform (i.e. never gets produced from a higher-order operation). That said, I'm describing the current behavior, not outlining any promises of future behavior. The "best" way to do this, if you feel you have to, is to just fully replace the primitive with an opaque object type; this is "guaranteed" to not encounter problems at the expensive of losing access to the underlying primitive's behavior. We do use some branding internally but don't file bugs against ourselves when we encounter weirdness 😉 |
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
TypeScript Version: nightly, 3.7.2, 3.6.3, 3.5.1 (issue occurs in all versions except 3.5.1)
Search Terms:
recursive, mapped, brand, branded, nominal
Code
Expected behavior:
InitialState
is typed as{ someString: Branded<'Foo', string> }
.Actual behavior:
InitialState
is typed as{ someString: never }
.Playground Link:
Here
Context:
This issue affects usage of
[email protected]
when callingRedux.createStore
.Redux.createStore
uses a recursive mapped type for thepreloadedState
. In my case,PreloadedState<S>
is incompatible withS
, becausePreloadedState<S>
containsnever
types andS
does not.The text was updated successfully, but these errors were encountered: