当前位置: 首页 > 知识库问答 >
问题:

如何键入接受具有超属性集的Context的Typescript React组件

鲁昕
2023-03-14

我正在尝试定义可重用的React组件,这些组件通过道具接受React. Context字段。它们可能不需要父上下文中可用的全部属性,并且,考虑到重用的愿望,可能会封装在具有不同上下文结构的提供程序中(但重用的子组件需要相同的核心属性)。例如,树中较高的父提供程序可能会定义Context类型,如下所示:

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 component in the tree, most likely in a different file*/}
      <SubComponent Context={SuperSetContext} />
    </SuperSetContext.Provider>
  );
}

子组件应该(我相信)能够用较少属性定义一个上下文属性,如下所示

const SubComponent: React.FunctionComponent<{
  Context: React.Context<{x: number, y: number}>
}> = ({ Context }) => {
  const { x, y } = useContext(props./Context);

  return (<div>{x + y}</div>)
}

或通过Pick

Context: React.Context<Pick<SuperSet, 'x' | 'y'>>

然而,当prop在Provider中分配时,上述子组件都会导致类型错误

<SubComponent Context={SuperSetContext} />
Type 'Context<SuperSet>' is not assignable to type 'Context<SubSet>'.
  Types of property 'Provider' are incompatible.
    Type 'Provider<SuperSet>' is not assignable to type 'Provider<SubSet>'.
      Types of parameters 'props' and 'props' are incompatible.
        Type 'ProviderProps<SubSet>' is not assignable to type 'ProviderProps<SuperSet>'.ts(2322)
test.tsx(26, 3): The expected type comes from property 'Context' which is declared here on type 'IntrinsicAttributes & { Context: Context<SubSet>; } & { children?: ReactNode; }'

我创建了一个Typescript Playground,在没有jsx的情况下对其进行测试,但无论使用jsx,都会发生这种情况。此外,我在天真的泛型类/函数中没有看到相同的行为。

那么,有没有办法用子集或上下文属性或不同的范例来定义子组件的上下文定义,以完成相同的设计并避免这种特定的类型不匹配呢?

共有2个答案

逄嘉禧
2023-03-14

在这种情况下,您应该使用通用组件(SubComponent),因为TS就在这里:您不能假设React.Context

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>)
}

你可以在操场上看到完整的例子:操场链接

沈华皓
2023-03-14

如果您声明您自己的扩展React. Context的接口

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>
  );
};

你可以在这个沙盒里看看

老实说,我无法解释导致行为差异的原因。

 类似资料:
  • 嵌套异常是com.fasterxml.jackson.databind.jsonMappingException:无法从START_OBJECT令牌反序列化java.lang.String实例

  • 全部显示 返回或设置一个字符串,该字符串确定指定命令栏的存储位置。该字符串由应用程序所定义和集成。String 类型,可读写。 说明 只能对自定义命令栏设置Context 属性。如果应用程序不能识别该上下文字符串,或不支持以编程方式修改上下文字符串的功能,那么该属性将失败。 示例 本示例显示一个消息框,该消息框包含命令栏“Custom”的上下文相关字符串。本示例运行于 Microsoft Word

  • 有人知道如何接受在Edge工作吗? 在Chrome 44,Firefox 39,IE 11,Opera 31中运行良好。

  • 问题内容: 然后,用户单击用户必须获得对话框。我正在使用此html属性和。但是在某些现代设备上,这不会发生。下面有代码示例和下表,说明其正常工作与否。代码示例在和中进行了测试。 TL; DR: 我只有5个代码示例: 1.() 2.() 3.() 4.() 5.() 测试设备: 三星S3(Android 4.1.2) 三星S3(Android 4.3) 三星Galaxy Tab 2 7.0(Andr

  • 问题内容: 我正在尝试合并一些视频,但出现时间戳错误。 我试图通过相同的尺寸,帧速率,采样率以及在没有音频轨道时添加音轨来使它们都相等。 错误消息如下所示:输出流0:0中的非单调DTS;前一个:8052684,当前:4127401; 更改为8052685。这可能会导致输出文件中的时间戳不正确。 问题答案: 因为这纯粹是一个ffmpeg使用问题,所以我将省略Python。由于我假设您的输入将是任意的

  • 问题内容: 每当三个作用域变量发生变化时,我都希望指令重新呈现HTML。前两个只是整数,第三个是数组。 我们必须观察几个变量,第三个参数带有,并且具有like ,但是带有隐含的。 有没有办法写类似这样的$ watch? 问题答案: 好吧,好像watchGroup不支持深度监视。因此,您可以通过注册一个匿名的深度监视程序,并通过监视功能传递值数组来进行黑客入侵。 演示版 或仅将此函数添加为rootS