admin管理员组文章数量:1425871
I'm trying to define re-usable React ponents that accept a React.Context field through a prop. They may not need the entirety of the properties available in the parent's context and, given the desire for reuse, may be encapsulated in Providers with different Context structures (but the same core properties needed by the reused sub ponent). For instance a parent provider higher in the tree may define the Context type like so:
type SuperSet = {
x: number,
y: number,
z: number
}
let superSet = {x: 1, y: 2, z: 3}
const SuperSetContext = React.createContext<SuperSet>(superSet)
const SuperSetProvider = (props) => {
return (
<SuperSetContext.Provider value={superSet}>
...
{/* Arbitrarily deep nested ponent in the tree, most likely in a different file*/}
<SubComponent Context={SuperSetContext} />
</SuperSetContext.Provider>
);
}
The SubComponent should (I believe) be able to define a Context prop with less properties like so
const SubComponent: React.FunctionComponent<{
Context: React.Context<{x: number, y: number}>
}> = ({ Context }) => {
const { x, y } = useContext(props./Context);
return (<div>{x + y}</div>)
}
Or via Pick<>
Context: React.Context<Pick<SuperSet, 'x' | 'y'>>
However either way the above SubComponent causes a type error when the prop is assigned within the Provider
<SubComponent Context={SuperSetContext} />
Type 'Context<SuperSet>' is not assignable to type 'Context<SubSet>'.
Types of property 'Provider' are inpatible.
Type 'Provider<SuperSet>' is not assignable to type 'Provider<SubSet>'.
Types of parameters 'props' and 'props' are inpatible.
Type 'ProviderProps<SubSet>' is not assignable to type 'ProviderProps<SuperSet>'.ts(2322)
test.tsx(26, 3): The expected type es from property 'Context' which is declared here on type 'IntrinsicAttributes & { Context: Context<SubSet>; } & { children?: ReactNode; }'
I created a Typescript Playground to test it without jsx but it occurs regardless of using jsx. Additionaly I don't see the same behavior with naive generic classes/functions.
So is there a way to define the SubComponent's Context definition with a subset or Context properties OR a different paradigm to acplish the same design and escape this particular typing mismatch?
I'm trying to define re-usable React ponents that accept a React.Context field through a prop. They may not need the entirety of the properties available in the parent's context and, given the desire for reuse, may be encapsulated in Providers with different Context structures (but the same core properties needed by the reused sub ponent). For instance a parent provider higher in the tree may define the Context type like so:
type SuperSet = {
x: number,
y: number,
z: number
}
let superSet = {x: 1, y: 2, z: 3}
const SuperSetContext = React.createContext<SuperSet>(superSet)
const SuperSetProvider = (props) => {
return (
<SuperSetContext.Provider value={superSet}>
...
{/* Arbitrarily deep nested ponent in the tree, most likely in a different file*/}
<SubComponent Context={SuperSetContext} />
</SuperSetContext.Provider>
);
}
The SubComponent should (I believe) be able to define a Context prop with less properties like so
const SubComponent: React.FunctionComponent<{
Context: React.Context<{x: number, y: number}>
}> = ({ Context }) => {
const { x, y } = useContext(props./Context);
return (<div>{x + y}</div>)
}
Or via Pick<>
Context: React.Context<Pick<SuperSet, 'x' | 'y'>>
However either way the above SubComponent causes a type error when the prop is assigned within the Provider
<SubComponent Context={SuperSetContext} />
Type 'Context<SuperSet>' is not assignable to type 'Context<SubSet>'.
Types of property 'Provider' are inpatible.
Type 'Provider<SuperSet>' is not assignable to type 'Provider<SubSet>'.
Types of parameters 'props' and 'props' are inpatible.
Type 'ProviderProps<SubSet>' is not assignable to type 'ProviderProps<SuperSet>'.ts(2322)
test.tsx(26, 3): The expected type es from property 'Context' which is declared here on type 'IntrinsicAttributes & { Context: Context<SubSet>; } & { children?: ReactNode; }'
I created a Typescript Playground to test it without jsx but it occurs regardless of using jsx. Additionaly I don't see the same behavior with naive generic classes/functions.
So is there a way to define the SubComponent's Context definition with a subset or Context properties OR a different paradigm to acplish the same design and escape this particular typing mismatch?
Share Improve this question asked Apr 16, 2020 at 3:19 ZacharyZachary 852 silver badges11 bronze badges2 Answers
Reset to default 4If you declare you own interface that extends React.Context<T>
, Typescript will accept it.
interface MyContext<T> extends React.Context<T> {} // this does the trick
const SubComponent: React.FunctionComponent<{
// use MyContext instead of React.Context
Context: MyContext<{x: number, y: number}>
}> = ({ Context }) => {
const { x, y } = React.useContext(Context);
return <div>{x + y}</div>;
};
// Now pass a SuperSet
type SuperSet = {
x: number;
y: number;
z: number;
};
let superSet = { x: 1, y: 2, z: 3 };
const SuperSetContext = React.createContext<SuperSet>(superSet);
const SuperSetProvider = props => {
return (
<SuperSetContext.Provider value={superSet}>
{/* No TS error! */}
<SubComponent Context={SuperSetContext} />
</SuperSetContext.Provider>
);
};
you can check it out in this sandbox
To be honest, I can't explain what causes the difference in behavior.
In this case you should use a generic ponent (SubComponent
), since TS is right here: you can't assume React.Context<SubSet>
is a subset of React.Context<SuperSet>
because they're boxed types. Using a simple generic ponent, you can work around this specifying what you really want: that the context type should be a subset:
function SubComponent<T extends { x: number, y: number }>(props: {
context: React.Context<T>
}) {
const { x, y } = React.useContext(props.context);
return (<div>{x + y}</div>)
}
You can see full example in the playground: Playground Link
本文标签:
版权声明:本文标题:javascript - How to type a Typescript React Component that accepts a Context with a super-set of properties - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745459460a2659256.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论