-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Mapped Types with Intersections in React Props Definition, results in type is not assignable error #27201
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
Comments
The line ComponentType<{ [PropKey in (keyof P | Key | 'loading' | 'error' | keyof MutationResult<TData>)]: PropKey extends Key ? MutationFn : PropKey extends keyof P ? P[PropKey] : PropKey extends keyof MutationResult<TData> ? MutationResult<TData>['data'][PropKey] : PropKey extends ('loading' | 'error') ? MutationResult<TData>[PropKey] : never; } |
even with What i'm guessing is the compiler can't figure out what after the mapped type is removed, the errors disappear |
Actually it appears the issue stems from the fact that the component props are being defined as a intersection of two readonly types. link to example: Repo |
Please reduce the repro further - thanks! |
reduced here |
It's worth nothing that the error is correct, if awful to diagnose (at least in your reduced example). In your simplified example: /** @format */
declare type Index = string | number | symbol
declare type Mapped<Key extends Index, T> = { [K in Key]: T }
declare type MutationFn<T, U> = any
type I<P, TData, Key extends string> = Readonly<{
children?: any;
}> & Readonly<P & TData & {
loading: boolean,
error: Error
} & Mapped<Key, MutationFn<any, any>>>
type Z<P, D, K extends string> = I<P, D, K>["loading"]
const loading: boolean = true
class Example<P, D, K extends string> {
isLoading: Z<P, D, K> = loading
}
type Other<P, TData, Key extends string> = Readonly<{
children?: any;
} & P & TData & {
loading: boolean,
error: Error
} & Mapped<Key, MutationFn<any, any>>>
type Tesr<P, D, K extends string> = Other<P, D, K>["loading"]
class Example2<P, D, K extends string> {
isLoading: Tesr<P, D, K> = loading
} if I instantiated |
That makes sense, but then why would it still error, if I mark it so that types P & D have any boolean properties excluded from the type? and also explicitly mark the mapped type that it returns something other than a boolean wouldnt that basically make it so that even if I instantiate |
Because |
|
Excepting possible compilation performance issues, it's best not to use the intersection operator ComponentType<{
[PropKey in (keyof P | Key | 'loading' | 'error' | keyof MutationResult<TData>)]: PropKey extends Key ?
MutationFn : PropKey extends keyof P ?
P[PropKey] : PropKey extends keyof MutationResult<TData> ?
MutationResult<TData>['data'][PropKey] : PropKey extends ('loading' | 'error') ?
MutationResult<TData>[PropKey] : never;
}> The value for Incidentally, the compiler will flatten the above described type if you ever call it with concrete types, making it rather easier to find type mismatches. Your example can also trivially be broken by calling: const ex = new Example<{}, {}, "loading">(); which will also break at runtime, since |
How does the Readonly type play into all this? It seems that the type only breaks when the intersection is of two Readonly types it will error out but if they aren't wrapped in Readonly it's completely fine |
The non-readonly case should also be an error; but for historical reasons it isn't. The presence of a generic mapped type (ie, read-only) causes us to defer the access and treat it as a type variable, which we can then actually calculate the constraint of and issue the error. The non-mapped-type case (incorrectly) eagerly looks up the type of the member and uses it as the target type. So instead of assigning to an effective |
So what's the best way to write the type so that {
[PropKey in
| keyof P
| Key
| 'loading'
| 'error'
| keyof MutationResult<TData>]: PropKey extends Key
? MutationFn
: PropKey extends keyof P
? P[PropKey]
: PropKey extends keyof MutationResult<TData>
? Result<TData>['data'][PropKey]
: PropKey extends ('loading' | 'error')
? { loading: boolean, error: Error }[PropKey]
: never
}["loading"] will resolve to boolean? and error would correctly resolve to the Error type? |
Search Terms:
Mapped Types with React Props
incorrect assignable reference
Code
the intent is for this to be a decorator
Expected behavior:
the props should be correct, for reference the mapped type behavior produces this I think
not actually sure why it's saying the type is not assignable since
type '((IntrinsicAttributes & IntrinsicClassAttributes<Component<P & Readonly<{ [K in Key]: MutationFn<any, OperationVariables>; }> & Pick<MutationResult, "data" | "loading" | "error">, any, any>> & Readonly<...> & Readonly<...>) | (IntrinsicAttributes & ... 2 more ... & { ...; }))["loading"]'
should evaluate to boolean.

Actual behavior:
Playground Link:
Related Issues:
The text was updated successfully, but these errors were encountered: