【问题标题】:JSX TypeScript definitions override for custom framework's components?JSX TypeScript 定义覆盖自定义框架的组件?
【发布时间】:2021-01-03 14:16:27
【问题描述】:

我正在开发一个开源 JS 框架,我想将 JSX 与 typescript 一起用于它的组件。但我对 JSX 的类型定义有疑问

TS 预期:

<Header title="Hello World" />

成为(对于任何类似反应的框架):

function Header(props: { title: string }) : JSXElement

虽然在此框架中,实际类型基于 Observables (RxJS):

function Header(props: Observable<{ title: string }>) : JSXElement | Observable<JSXElement>

例如一个简单的h1 标头组件:

function Header(props$) { // take in a stream of updates
  return props$.pipe(     // return a stream of JSX updates
    map(props => <h1>{ props.title }</h1>)
  );
}

因此,组件接收一个 Observable 属性并返回一个静态 JSX 元素或 JSX 元素流。

UPD 澄清: 框架已经按照我描述的那样工作,打字是问题。 Observables 在引擎 runtime 中处理,而不是在转换阶段,因此 JSX 转换为 createElement 就可以了。我只需要调整 TSX 的类型,例如:

// current:
createElement<P>(fn : (props: P) => JSXElement, props: P, ...children: JSXElement[])

// should be:
createElement<P>(fn : (props: Observable<P>) => JSXElement, props: P, ...children: JSXElement[])

我看到可以部分自定义JSX,但我还没有找到一种方法来覆盖它。我试图覆盖 JSX.Element 和 JSX.ElementType ,而对打字结果没有任何明显的变化。

甚至可以进行这种覆盖吗?

我应该覆盖哪些类型/接口?

谢谢!

~~我没有链接repo不要被怀疑在广告中~~

UPD:有关详细信息,您可以在此处找到框架:http://recks.gitbook.io/

【问题讨论】:

  • 我几乎可以肯定,您不会在组件内收到您的 Observable。它将在 React.createElement 中丢失。我看到传递 Observable 的唯一方法是作为值。单个道具或通过上下文。
  • 嘿,@Thomas!这是一个自定义框架,它提供了自己的createElement 和处理 Observables(进出)的引擎。所以它已经像我上面描述的那样工作了,我只想添加适当的类型来改善开发体验
  • @arslan2012,afaik,JSX 是 TS 中的一种特殊子语法,TSC 完全有能力进行转换。此外,createElement(fn, props, ...children) 转换对我来说很好,可观察部分在引擎中处理——所以我不需要自定义转换——只需输入。基本上我需要告诉 TS createElement&lt;P&gt;(fn : (props: P) =&gt; any, props: P, ...children: any[]) 现在是 createElement&lt;P&gt;(fn : (props: Observable&lt;P&gt;) =&gt; any, props: P, ...children: any[])。抱歉没有说清楚,会更新 Q 以更好地反映这一点。

标签: javascript typescript rxjs jsx typescript-typings


【解决方案1】:

似乎LibraryManagedAttributes 可以执行我正在寻找的覆盖。

Preact uses it 将defaultProps 添加到组件类型:

type LibraryManagedAttributes<Component, Props> = Component extends {
    defaultProps: infer Defaults;
}
    ? Defaultize<Props, Defaults>
    : Props;

所以我同样用:

type LibraryManagedAttributes<Component, Props> =
    Props extends Observable<infer O>
    ? O
    : EmptyProps;

interface EmptyProps {}

EmptyProps 是一种 hack,可确保没有正确类型的组件不会接受属性。

它似乎有效(至少,影响类型):

注意:如此屏幕截图所示,您需要通过命名空间 global.[LIB_NS].JSX 或直接通过 global.JSX 覆盖 JSX 的内置 TS 定义。更多详情请查看官方文档最底部部分:https://www.typescriptlang.org/docs/handbook/jsx.html#factory-functions

非常感谢 Josep M Sobrepere 给了我关于 preact 的 LibraryManagedAttributes 覆盖的提示! ?

如果您知道更多详细信息,请随时添加您的答案

【讨论】:

    【解决方案2】:

    尝试覆盖和自定义node_modules/@types/react/index.d.ts 和node_modules/@babel/types/lib/index.d.ts 我能够将React.FC 设置为{foo: 'bar'} 类型,并将JSXElement 更新为具有相同类型,然后编写一个返回该对象的组件& 渲染它而不产生类型错误。我正在通过修改 React 项目中的类型进行测试。我没有用你的库进行测试,但我认为关键是不要加载 React 类型,而是加载你自己的类型。类型实际上是全局的这一事实是更大的问题,您的项目的使用者可能需要单独的 tsconfig 文件才能通过这种方法在同一个项目中使用两个库。

    【讨论】:

    • 嗨,乔希!感谢您抽出宝贵的时间!据我了解,问题不是 如何 覆盖,而是 what 覆盖。似乎 TS 已经与一些 TSX 定义捆绑在一起(在 React 添加它的 d.ts 之前),尽管 TS 允许我们通过命名空间 global.[LIB_NS].JSX 或直接通过 global.JSX 覆盖它的定义(参见我兄弟答案中的屏幕截图,以及typescriptlang.org/docs/handbook/jsx.html#factory-functions 最底部的文档)。不确定,但希望包括此覆盖就足够了。如果我遗漏了什么,请告诉我
    猜你喜欢
    • 2023-03-21
    • 2020-04-28
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多