Skip to content

Commit 7c4f3b0

Browse files
mohit-negieps1lon
andauthored
replace usage of deprecated global JSX in favor of React.JSX (typescript-cheatsheets#659)
* fixes usage of deprecated JSX.Element to React.JSX.Element typescript-cheatsheets#643 * gen-readme * Migrate away from all usage of deprecated global JSX * one more --------- Co-authored-by: eps1lon <[email protected]>
1 parent f7423d9 commit 7c4f3b0

File tree

9 files changed

+49
-47
lines changed

9 files changed

+49
-47
lines changed

README.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ type AppProps = {
190190
const App = ({ message }: AppProps) => <div>{message}</div>;
191191

192192
// you can choose annotate the return type so an error is raised if you accidentally return some other type
193-
const App = ({ message }: AppProps): JSX.Element => <div>{message}</div>;
193+
const App = ({ message }: AppProps): React.JSX.Element => <div>{message}</div>;
194194

195195
// you can also inline the type declaration; eliminates naming the prop types, but looks repetitive
196196
const App = ({ message }: { message: string }) => <div>{message}</div>;
@@ -921,11 +921,11 @@ let el = <Greet age={3} />;
921921
```
922922

923923
<details>
924-
<summary><b><code>JSX.LibraryManagedAttributes</code> nuance for library authors</b></summary>
924+
<summary><b><code>React.JSX.LibraryManagedAttributes</code> nuance for library authors</b></summary>
925925

926926
The above implementations work fine for App creators, but sometimes you want to be able to export `GreetProps` so that others can consume it. The problem here is that the way `GreetProps` is defined, `age` is a required prop when it isn't because of `defaultProps`.
927927

928-
The insight to have here is that [`GreetProps` is the _internal_ contract for your component, not the _external_, consumer facing contract](https://github.com/typescript-cheatsheets/react/issues/66#issuecomment-453878710). You could create a separate type specifically for export, or you could make use of the `JSX.LibraryManagedAttributes` utility:
928+
The insight to have here is that [`GreetProps` is the _internal_ contract for your component, not the _external_, consumer facing contract](https://github.com/typescript-cheatsheets/react/issues/66#issuecomment-453878710). You could create a separate type specifically for export, or you could make use of the `React.JSX.LibraryManagedAttributes` utility:
929929

930930
```tsx
931931
// internal contract, should not be exported out
@@ -938,7 +938,7 @@ class Greet extends Component<GreetProps> {
938938
}
939939

940940
// external contract
941-
export type ApparentGreetProps = JSX.LibraryManagedAttributes<
941+
export type ApparentGreetProps = React.JSX.LibraryManagedAttributes<
942942
typeof Greet,
943943
GreetProps
944944
>;
@@ -978,13 +978,13 @@ const el = <TestComponent name="foo" />;
978978

979979
##### Solution
980980

981-
Define a utility that applies `JSX.LibraryManagedAttributes`:
981+
Define a utility that applies `React.JSX.LibraryManagedAttributes`:
982982

983983
```tsx
984984
type ComponentProps<T> = T extends
985985
| React.ComponentType<infer P>
986986
| React.Component<infer P>
987-
? JSX.LibraryManagedAttributes<T, P>
987+
? React.JSX.LibraryManagedAttributes<T, P>
988988
: never;
989989

990990
const TestComponent = (props: ComponentProps<typeof GreetComponent>) => {
@@ -1044,7 +1044,7 @@ export class MyComponent extends React.Component<IMyComponentProps> {
10441044
}
10451045
```
10461046

1047-
The problem with this approach is it causes complex issues with the type inference working with `JSX.LibraryManagedAttributes`. Basically it causes the compiler to think that when creating a JSX expression with that component, that all of its props are optional.
1047+
The problem with this approach is it causes complex issues with the type inference working with `React.JSX.LibraryManagedAttributes`. Basically it causes the compiler to think that when creating a JSX expression with that component, that all of its props are optional.
10481048

10491049
[See commentary by @ferdaber here](https://github.com/typescript-cheatsheets/react/issues/57) and [here](https://github.com/typescript-cheatsheets/react/issues/61).
10501050

@@ -1143,7 +1143,7 @@ Relevant for components that accept other React components as props.
11431143
```tsx
11441144
export declare interface AppProps {
11451145
children?: React.ReactNode; // best, accepts everything React can render
1146-
childrenElement: JSX.Element; // A single React element
1146+
childrenElement: React.JSX.Element; // A single React element
11471147
style?: React.CSSProperties; // to pass through style props
11481148
onChange?: React.FormEventHandler<HTMLInputElement>; // form events! the generic parameter is the type of event.target
11491149
// more info: https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase/#wrappingmirroring
@@ -1179,16 +1179,16 @@ This is because `ReactNode` includes `ReactFragment` which allowed type `{}` bef
11791179
</details>
11801180

11811181
<details>
1182-
<summary><b>JSX.Element vs React.ReactNode?</b></summary>
1182+
<summary><b>React.JSX.Element vs React.ReactNode?</b></summary>
11831183

1184-
Quote [@ferdaber](https://github.com/typescript-cheatsheets/react/issues/57): A more technical explanation is that a valid React node is not the same thing as what is returned by `React.createElement`. Regardless of what a component ends up rendering, `React.createElement` always returns an object, which is the `JSX.Element` interface, but `React.ReactNode` is the set of all possible return values of a component.
1184+
Quote [@ferdaber](https://github.com/typescript-cheatsheets/react/issues/57): A more technical explanation is that a valid React node is not the same thing as what is returned by `React.createElement`. Regardless of what a component ends up rendering, `React.createElement` always returns an object, which is the `React.JSX.Element` interface, but `React.ReactNode` is the set of all possible return values of a component.
11851185

1186-
- `JSX.Element` -> Return value of `React.createElement`
1186+
- `React.JSX.Element` -> Return value of `React.createElement`
11871187
- `React.ReactNode` -> Return value of a component
11881188

11891189
</details>
11901190

1191-
[More discussion: Where ReactNode does not overlap with JSX.Element](https://github.com/typescript-cheatsheets/react/issues/129)
1191+
[More discussion: Where ReactNode does not overlap with React.JSX.Element](https://github.com/typescript-cheatsheets/react/issues/129)
11921192

11931193
[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new).
11941194

docs/advanced/patterns_by_usecase.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,20 @@ You CAN use `ComponentProps` in place of `ComponentPropsWithRef`, but you may pr
5050

5151
More info: https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/forward_and_create_ref/
5252

53-
### Maybe `JSX.IntrinsicElements` or `[Element]HTMLAttributes`
53+
### Maybe `React.JSX.IntrinsicElements` or `[Element]HTMLAttributes`
5454

5555
There are at least 2 other equivalent ways to do this, but they are more verbose:
5656

5757
```tsx
58-
// Method 1: JSX.IntrinsicElements
59-
type BtnType = JSX.IntrinsicElements["button"]; // cannot inline or will error
58+
// Method 1: React.JSX.IntrinsicElements
59+
type BtnType = React.JSX.IntrinsicElements["button"]; // cannot inline or will error
6060
export interface ButtonProps extends BtnType {} // etc
6161

6262
// Method 2: React.[Element]HTMLAttributes
6363
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>
6464
```
6565
66-
Looking at [the source for `ComponentProps`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/f3134f4897c8473f590cbcdd5788da8d59796f45/types/react/index.d.ts#L821) shows that this is a clever wrapper for `JSX.IntrinsicElements`, whereas the second method relies on specialized interfaces with unfamiliar naming/capitalization.
66+
Looking at [the source for `ComponentProps`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/f3134f4897c8473f590cbcdd5788da8d59796f45/types/react/index.d.ts#L821) shows that this is a clever wrapper for `React.JSX.IntrinsicElements`, whereas the second method relies on specialized interfaces with unfamiliar naming/capitalization.
6767
6868
> Note: There are over 50 of these specialized interfaces available - look for `HTMLAttributes` in our [`@types/react` commentary](https://react-typescript-cheatsheet.netlify.app/docs/advanced/types_react_api#typesreact).
6969
@@ -375,7 +375,7 @@ Parent.propTypes = {
375375

376376
The thing you cannot do is **specify which components** the children are, e.g. If you want to express the fact that "React Router `<Routes>` can only have `<Route>` as children, nothing else is allowed" in TypeScript.
377377

378-
This is because when you write a JSX expression (`const foo = <MyComponent foo='foo' />`), the resultant type is blackboxed into a generic JSX.Element type. (_[thanks @ferdaber](https://github.com/typescript-cheatsheets/react/issues/271)_)
378+
This is because when you write a JSX expression (`const foo = <MyComponent foo='foo' />`), the resultant type is blackboxed into a generic React.JSX.Element type. (_[thanks @ferdaber](https://github.com/typescript-cheatsheets/react/issues/271)_)
379379

380380
## Type Narrowing based on Props
381381

@@ -414,8 +414,8 @@ type AnchorProps = React.AnchorHTMLAttributes<HTMLAnchorElement> & {
414414

415415
// Input/output options
416416
type Overload = {
417-
(props: ButtonProps): JSX.Element;
418-
(props: AnchorProps): JSX.Element;
417+
(props: ButtonProps): React.JSX.Element;
418+
(props: AnchorProps): React.JSX.Element;
419419
};
420420

421421
// Guard to check if href exists in props
@@ -438,8 +438,8 @@ Components, and JSX in general, are analogous to functions. When a component can
438438
A very common use case for this is to render something as either a button or an anchor, based on if it receives a `href` attribute.
439439

440440
```tsx
441-
type ButtonProps = JSX.IntrinsicElements["button"];
442-
type AnchorProps = JSX.IntrinsicElements["a"];
441+
type ButtonProps = React.JSX.IntrinsicElements["button"];
442+
type AnchorProps = React.JSX.IntrinsicElements["a"];
443443

444444
// optionally use a custom type guard
445445
function isPropsForAnchorElement(
@@ -460,7 +460,9 @@ function Clickable(props: ButtonProps | AnchorProps) {
460460
They don't even need to be completely different props, as long as they have at least one difference in properties:
461461

462462
```tsx
463-
type LinkProps = Omit<JSX.IntrinsicElements["a"], "href"> & { to?: string };
463+
type LinkProps = Omit<React.JSX.IntrinsicElements["a"], "href"> & {
464+
to?: string;
465+
};
464466

465467
function RouterLink(props: LinkProps | AnchorProps) {
466468
if ("href" in props) {
@@ -808,8 +810,8 @@ type NoTruncateProps = CommonProps & { truncate?: false };
808810
type TruncateProps = CommonProps & { truncate: true; expanded?: boolean };
809811

810812
// Function overloads to accept both prop types NoTruncateProps & TruncateProps
811-
function Text(props: NoTruncateProps): JSX.Element;
812-
function Text(props: TruncateProps): JSX.Element;
813+
function Text(props: NoTruncateProps): React.JSX.Element;
814+
function Text(props: TruncateProps): React.JSX.Element;
813815
function Text(props: CommonProps & { truncate?: boolean; expanded?: boolean }) {
814816
const { children, truncate, expanded, ...otherProps } = props;
815817
const classNames = truncate ? ".truncate" : "";

docs/advanced/types-react-ap.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Not Commonly Used but Good to know
3737
- `ComponentProps` - props of a component - most useful for [Wrapping/Mirroring a HTML Element](https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase#wrappingmirroring-a-html-element)
3838
- `ComponentPropsWithRef` - props of a component where if it is a class-based component it will replace the `ref` prop with its own instance type
3939
- `ComponentPropsWithoutRef` - props of a component without its `ref` prop
40-
- `HTMLProps` and `HTMLAttributes` - these are the most generic versions, for global attributes (see a list of [attributes marked as "global attribute" on MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes)). In general, prefer `React.ComponentProps`, `JSX.IntrinsicElements`, or [specialized HTMLAttributes interfaces](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/a2aa0406e7bf269eef01292fcb2b24dee89a7d2b/types/react/index.d.ts#L1914-L2625):
40+
- `HTMLProps` and `HTMLAttributes` - these are the most generic versions, for global attributes (see a list of [attributes marked as "global attribute" on MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes)). In general, prefer `React.ComponentProps`, `React.JSX.IntrinsicElements`, or [specialized HTMLAttributes interfaces](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/a2aa0406e7bf269eef01292fcb2b24dee89a7d2b/types/react/index.d.ts#L1914-L2625):
4141

4242
<details>
4343
<summary>
@@ -102,7 +102,7 @@ Note that there are about 50 of these, which means there are some HTML elements
102102

103103
- all methods: `createElement`, `cloneElement`, ... are all public and reflect the React runtime API
104104

105-
[@Ferdaber's note](https://github.com/typescript-cheatsheets/react/pull/69): I discourage the use of most `...Element` types because of how black-boxy `JSX.Element` is. You should almost always assume that anything produced by `React.createElement` is the base type `React.ReactElement`.
105+
[@Ferdaber's note](https://github.com/typescript-cheatsheets/react/pull/69): I discourage the use of most `...Element` types because of how black-boxy `React.JSX.Element` is. You should almost always assume that anything produced by `React.createElement` is the base type `React.ReactElement`.
106106

107107
**Namespace: JSX**
108108

docs/basic/getting-started/basic-type-examples.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ Relevant for components that accept other React components as props.
8888
```tsx
8989
export declare interface AppProps {
9090
children?: React.ReactNode; // best, accepts everything React can render
91-
childrenElement: JSX.Element; // A single React element
91+
childrenElement: React.JSX.Element; // A single React element
9292
style?: React.CSSProperties; // to pass through style props
9393
onChange?: React.FormEventHandler<HTMLInputElement>; // form events! the generic parameter is the type of event.target
9494
// more info: https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase/#wrappingmirroring
@@ -124,16 +124,16 @@ This is because `ReactNode` includes `ReactFragment` which allowed type `{}` bef
124124
</details>
125125

126126
<details>
127-
<summary><b>JSX.Element vs React.ReactNode?</b></summary>
127+
<summary><b>React.JSX.Element vs React.ReactNode?</b></summary>
128128

129-
Quote [@ferdaber](https://github.com/typescript-cheatsheets/react/issues/57): A more technical explanation is that a valid React node is not the same thing as what is returned by `React.createElement`. Regardless of what a component ends up rendering, `React.createElement` always returns an object, which is the `JSX.Element` interface, but `React.ReactNode` is the set of all possible return values of a component.
129+
Quote [@ferdaber](https://github.com/typescript-cheatsheets/react/issues/57): A more technical explanation is that a valid React node is not the same thing as what is returned by `React.createElement`. Regardless of what a component ends up rendering, `React.createElement` always returns an object, which is the `React.JSX.Element` interface, but `React.ReactNode` is the set of all possible return values of a component.
130130

131-
- `JSX.Element` -> Return value of `React.createElement`
131+
- `React.JSX.Element` -> Return value of `React.createElement`
132132
- `React.ReactNode` -> Return value of a component
133133

134134
</details>
135135

136-
[More discussion: Where ReactNode does not overlap with JSX.Element](https://github.com/typescript-cheatsheets/react/issues/129)
136+
[More discussion: Where ReactNode does not overlap with React.JSX.Element](https://github.com/typescript-cheatsheets/react/issues/129)
137137

138138
[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new).
139139

docs/basic/getting-started/default-props.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ let el = <Greet age={3} />;
8080
```
8181

8282
<details>
83-
<summary><b><code>JSX.LibraryManagedAttributes</code> nuance for library authors</b></summary>
83+
<summary><b><code>React.JSX.LibraryManagedAttributes</code> nuance for library authors</b></summary>
8484

8585
The above implementations work fine for App creators, but sometimes you want to be able to export `GreetProps` so that others can consume it. The problem here is that the way `GreetProps` is defined, `age` is a required prop when it isn't because of `defaultProps`.
8686

87-
The insight to have here is that [`GreetProps` is the _internal_ contract for your component, not the _external_, consumer facing contract](https://github.com/typescript-cheatsheets/react/issues/66#issuecomment-453878710). You could create a separate type specifically for export, or you could make use of the `JSX.LibraryManagedAttributes` utility:
87+
The insight to have here is that [`GreetProps` is the _internal_ contract for your component, not the _external_, consumer facing contract](https://github.com/typescript-cheatsheets/react/issues/66#issuecomment-453878710). You could create a separate type specifically for export, or you could make use of the `React.JSX.LibraryManagedAttributes` utility:
8888

8989
```tsx
9090
// internal contract, should not be exported out
@@ -97,7 +97,7 @@ class Greet extends Component<GreetProps> {
9797
}
9898

9999
// external contract
100-
export type ApparentGreetProps = JSX.LibraryManagedAttributes<
100+
export type ApparentGreetProps = React.JSX.LibraryManagedAttributes<
101101
typeof Greet,
102102
GreetProps
103103
>;
@@ -137,13 +137,13 @@ const el = <TestComponent name="foo" />;
137137

138138
### Solution
139139

140-
Define a utility that applies `JSX.LibraryManagedAttributes`:
140+
Define a utility that applies `React.JSX.LibraryManagedAttributes`:
141141

142142
```tsx
143143
type ComponentProps<T> = T extends
144144
| React.ComponentType<infer P>
145145
| React.Component<infer P>
146-
? JSX.LibraryManagedAttributes<T, P>
146+
? React.JSX.LibraryManagedAttributes<T, P>
147147
: never;
148148

149149
const TestComponent = (props: ComponentProps<typeof GreetComponent>) => {
@@ -203,7 +203,7 @@ export class MyComponent extends React.Component<IMyComponentProps> {
203203
}
204204
```
205205

206-
The problem with this approach is it causes complex issues with the type inference working with `JSX.LibraryManagedAttributes`. Basically it causes the compiler to think that when creating a JSX expression with that component, that all of its props are optional.
206+
The problem with this approach is it causes complex issues with the type inference working with `React.JSX.LibraryManagedAttributes`. Basically it causes the compiler to think that when creating a JSX expression with that component, that all of its props are optional.
207207

208208
[See commentary by @ferdaber here](https://github.com/typescript-cheatsheets/react/issues/57) and [here](https://github.com/typescript-cheatsheets/react/issues/61).
209209

docs/basic/getting-started/function-components.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type AppProps = {
1515
const App = ({ message }: AppProps) => <div>{message}</div>;
1616

1717
// you can choose annotate the return type so an error is raised if you accidentally return some other type
18-
const App = ({ message }: AppProps): JSX.Element => <div>{message}</div>;
18+
const App = ({ message }: AppProps): React.JSX.Element => <div>{message}</div>;
1919

2020
// you can also inline the type declaration; eliminates naming the prop types, but looks repetitive
2121
const App = ({ message }: { message: string }) => <div>{message}</div>;

docs/hoc/excluding-props.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function withOwner(owner: string) {
6969
return function <T extends { owner: string }>(
7070
Component: React.ComponentType<T>
7171
) {
72-
return function (props: Omit<T, "owner">): JSX.Element {
72+
return function (props: Omit<T, "owner">): React.JSX.Element {
7373
const newProps = { ...props, owner } as T;
7474
return <Component {...newProps} />;
7575
};
@@ -94,7 +94,7 @@ function withInjectedProps<U extends Record<string, unknown>>(
9494
injectedProps: U
9595
) {
9696
return function <T extends U>(Component: React.ComponentType<T>) {
97-
return function (props: Omit<T, keyof U>): JSX.Element {
97+
return function (props: Omit<T, keyof U>): React.JSX.Element {
9898
//A type coercion is neccessary because TypeScript doesn't know that the Omit<T, keyof U> + {...injectedProps} = T
9999
const newProps = { ...props, ...injectedProps } as T;
100100
return <Component {...newProps} />;

docs/hoc/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ const withSampleHoC = <P extends {}>(
2929

3030
componentName = component.displayName ?? component.name
3131
): {
32-
(props: P): JSX.Element;
32+
(props: P): React.JSX.Element;
3333
displayName: string;
3434
} => {
3535

3636
function WithSampleHoc(props: P) {
3737
//Do something special to justify the HoC.
38-
return component(props) as JSX.Element;
38+
return component(props) as React.JSX.Element;
3939
}
4040

4141
WithSampleHoc.displayName = `withSampleHoC(${componentName})`;
@@ -50,7 +50,7 @@ const withSampleHoC = <P extends {}>(
5050
5151
This code meets these criteria:
5252
53-
1. Allows a component to return valid elements (`strings | array | boolean | null | number`) and not just `JSX.Element | null`.
53+
1. Allows a component to return valid elements (`strings | array | boolean | null | number`) and not just `React.JSX.Element | null`.
5454
2. Wraps it in a memo unless you opt out.
5555
3. Removes the nested component, so React Dev tools will just show one component.
5656
4. Indicates with `displayName` in React Dev Tool with an annotation that this is a component wrapped in two HoCs

0 commit comments

Comments
 (0)