React 18 alpha已经发布,我们如何用TypeScript来使用它呢?
用TypeScript创建一个React应用程序
让我们用Create React App为自己创建一个React TypeScript应用程序。
yarn create react-app my-app --template typescript
现在把React的版本升级到@next
。
yarn add react@next react-dom@next
这将使你在package.json
使用React 18的条目。它可能会看起来像这样:
"react": "^18.0.0-alpha-e6be2d531",
"react-dom": "^18.0.0-alpha-e6be2d531",
如果运行yarn start
,就会发现自己在运行一个React 18应用程序。
使用新的API
因此,尝试使用 [ReactDOM.createRoot](https://github.com/reactwg/react-18/discussions/5)
API。正是这个API使我们的应用程序可以使用React 18的新功能。我们将打开index.tsx
,并进行这一改变:
-ReactDOM.render(
- <React.StrictMode>
- <App />
- </React.StrictMode>,
- document.getElementById('root')
-);
如果单独运行JavaScript,到这就可以了。然而,由于我们也在使用TypeScript,现在就遇到了一个错误。
Property 'createRoot' does not exist on type 'typeof import("/code/my-app/node_modules/@types/react-dom/index")'. TS2339
这是TypeScript编译器不了解ReactDOM.createRoot
。这是因为目前我们的应用程序中的类型定义没有定义该API。
所以升级我们的类型定义。
yarn add @types/react @types/react-dom
可惜同样的错误又出现了。
告诉TypeScript关于新的API的信息
如果看一下为API添加支持的PR,我们会发现一些提示。从next.d.ts发现这个信息。
/**
* These are types for things that are present in the upcoming React 18 release.
*
* Once React 18 is released they can just be moved to the main index file.
*
* To load the types declared here in an actual project, there are three ways. The easiest one,
* if your `tsconfig.json` already has a `"types"` array in the `"compilerOptions"` section,
* is to add `"react/next"` to the `"types"` array.
*
* Alternatively, a specific import syntax can to be used from a typescript file.
* This module does not exist in reality, which is why the {} is important:
*
* ```ts
* import {} from 'react/next'
* ```
*
* It is also possible to include it through a triple-slash reference:
*
* ```ts
* /// <reference types="react/next" />
* ```
*
* Either the import or the reference only needs to appear once, anywhere in the project.
*/
接下来试试清单上的第一项。编辑我们的tsconfig.json
,在"compilerOptions"
部分添加一个新条目。
"types": ["react/next", "react-dom/next"]
如果我们用yarn start
重新启动我们的构建,现在会看到一个不同的错误。
Argument of type 'HTMLElement | null' is not assignable to parameter of type 'Element | Document | DocumentFragment | Comment'. Type 'null' is not assignable to type 'Element | Document | DocumentFragment | Comment'. TS2345
这实际上与我们新的React类型定义的问题无关。这是 TypeScript 表示:"我们不能保证document.getElementById('root')
返回的东西不是null
。由于我们是在strictNullChecks
模式下,你需要确定root
不是空的。"
将通过在调用ReactDOM.createRoot
之前测试我们是否有一个元素在发挥作用来处理这个问题。
-const root = ReactDOM.createRoot(document.getElementById('root'));
+const rootElement = document.getElementById('root');
+if (!rootElement) throw new Error('Failed to find the root element');
+const root = ReactDOM.createRoot(rootElement);
随着这一改变,就有了一个使用TypeScript的React 18应用程序。