Stack Overflow Asked by kos on January 2, 2021
I’m working on an opensource JS framework and I want to use JSX with typescript for it’s components. But I have an issue with type definitions for JSX
TS expects:
<Header title="Hello World" />
to be (for any react-like framework):
function Header(props: { title: string }) : JSXElement
While in this framework the actual type is based on Observables (RxJS):
function Header(props: Observable<{ title: string }>) : JSXElement | Observable<JSXElement>
E.g. a simple h1
header component:
function Header(props$) { // take in a stream of updates
return props$.pipe( // return a stream of JSX updates
map(props => <h1>{ props.title }</h1>)
);
}
So, components receive an Observable of properties and return a static JSX element or a stream of JSX elements.
UPD to clarify: The framework already works as I described, the typings is the issue. Observables are handled in the engine runtime, not in the transformation phase, so JSX transformation to createElement
is fine. I just need to adjust typings for TSX, something like:
// current:
createElement<P>(fn : (props: P) => JSXElement, props: P, ...children: JSXElement[])
// should be:
createElement<P>(fn : (props: Observable<P>) => JSXElement, props: P, ...children: JSXElement[])
I see that one can partially customize JSX but I haven’t found a way to override that. I’ve tried to override JSX.Element
and JSX.ElementType
w/o any visible change to typings outcome.
Is it even possible to do this override?
What types/interfaces should I override?
Thanks!
~~I’m not linking the repo not to be suspected in advertising~~
UPD: For details, you can find the framework here: http://recks.gitbook.io/
It seems like LibraryManagedAttributes
can do the override I was looking for.
Preact uses it to add defaultProps
to component types:
type LibraryManagedAttributes<Component, Props> = Component extends {
defaultProps: infer Defaults;
}
? Defaultize<Props, Defaults>
: Props;
So I similarly overrode it with:
type LibraryManagedAttributes<Component, Props> =
Props extends Observable<infer O>
? O
: EmptyProps;
interface EmptyProps {}
EmptyProps
is a hack to ensure components w/o proper type won't accept attributes.
It seem to work (at least, affect the types):
NOTE: as shown in this screenshot, you'll need to override built-in TS definitions for JSX via a namespace global.[LIB_NS].JSX
or directly via global.JSX
. For more details, see the section at the very bottom of official docs: https://www.typescriptlang.org/docs/handbook/jsx.html#factory-functions
Big thanks goes to Josep M Sobrepere for giving me a hint on preact's LibraryManagedAttributes
override! ?
Please, feel free to add your answer if you know more details
Correct answer by kos on January 2, 2021
Try overriding and customizing node_modules/@types/react/index.d.ts
and node_modules/@babel/types/lib/index.d.ts
I was able to set React.FC
to the type {foo: 'bar'}
and also update the JSXElement
to have the same type, and then write a component that returns that object & renders it without producing a type error. I am testing by modifying the typings in a React project. I didn't test with your library, but I think the key is to not load the React typings and instead load your own typings. The fact the typings are effectively global is the larger issue, consumers of your project may need separate tsconfig files to use both libs in the same project with this approach.
Answered by Josh Ribakoff on January 2, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP