脚本宝典收集整理的这篇文章主要介绍了

翻译 | 开始使用 TypeScript 和 React

脚本宝典小编觉得挺不错的,现在分享给大家,也给大家做个参考,希望能帮助你少写一行代码,多一份安全和惬意。
<p><code></p> <ul> <li>原文地址:<a href="http://javascriptplayground.com/blog/2017/04/react-typescript/" rel="nofollow noreferrer" target="_blank">Getting started with TypeScript and React</a> </li> <li>原文作者:<a href="https://twitter.com/Jack_Franklin" rel="nofollow noreferrer" target="_blank">Jack_Franklin</a> </li> <li>译者:luxj</li> <li>校对者:veizz</li> </ul> <p><a href="https://medium.com/@tomdale/glimmer-js-whats-the-deal-with-typescript-f666d1a3aad0" rel="nofollow noreferrer" target="_blank">Tom Dale</a> 和其他人有一些关于 TypeScript 比较好的博文,跟随这些博文,我最近开始使用 TypeScript。今天,我将展示如何从零开始建立一个 TypeScript 工程,以及如何使用 Webpack 管理构建过程。我也将陈述关于 TypeScript 的第一印象,尤其是使用 TypeScript 和 <a href="http://www.js-code.com/tag/react" title="React" target="_blank">React</a>JS。</p> <p>我不会深入到 TypeScript 语法的具体细节,你可以阅读 <a href="https://www.typescriptlang.org/docs/tutorial.html" rel="nofollow noreferrer" target="_blank">TypeScript handbook</a> 或者免费书籍 <a href="https://basarat.gitbooks.io/typescript/content/docs/getting-started.html" rel="nofollow noreferrer" target="_blank">TypeScript Deep Dive</a>,它们是关于 TypeScript 比较好的入门材料。</p> <p><strong>更新:</strong>如果你想用德语阅读这篇文章,你可以 <a href="https://reactx.de/artikel/reactjs-typescript/" rel="nofollow noreferrer" target="_blank">thanks to the awesome folks at Reactx.de</a></p> <h2 id="articleHeader0">安装配置 TypeScript</h2> <p>第一步要做的事情是使用 Yarn 将 TypeScript 安装到本地的 <code><a href="http://www.js-code.com/tag/node" title="node" target="_blank">node</a>_modules</code> 目录,首先,使用 <code>yarn <a href="http://www.js-code.com/tag/in" title="in" target="_blank">in</a>it</code> 创建一个工程:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="yarn init yarn add typescript" title="" data-original-title="复制"></span> </div> </p></div> <pre class="shell hljs"><code class="shell">yarn <a href="http://www.js-code.com/tag/in" title="浏览关于“in”的文章" target="_blank" class="tag_link">in</a>it yarn add typescript</code></pre> <p>当你安装了 TypeScript,你就可以使用 <code>tsc</code> 命令行工具,这个工具可以编译 TypeScript,编译时会创建一个开始文件 <code>tsconfig.json</code>,你可以编辑这个文件。你可以运行 <code>tsc --<a href="http://www.js-code.com/tag/in" title="in" target="_blank">in</a>it</code> 获得这个文件 — 如果你已经在本地安装了 <code>TypeScript</code>,你需要运行 <code>./<a href="http://www.js-code.com/tag/node" title="node" target="_blank">node</a>_modules/.bin/tsc --init</code>。</p> <p><strong>注意:</strong><a href="https://github.com/jackfranklin/dotfiles/blob/master/zsh/zshrc#L101" rel="nofollow noreferrer" target="_blank">你可以在我的点开头的配置文件中看到</a>,我将 <code>$PATH</code> 定义为 <code>./<a href="http://www.js-code.com/tag/node" title="浏览关于“node”的文章" target="_blank" class="tag_link">node</a>_modules/.bin</code> 这个目录。这有点危险,因为我可能不经意地运行这个目录下的任何可执行的文件,但是我愿意承担这个风险,因为我知道这个目录下安装了什么,而且这能节省很多打字时间!</p> <p><code>tsc --init</code> 这个命令会生成一个 <code>tsconfig.json</code> 文件,所有 <code>TypeScript</code> 编译器的配置都存在于这个文件中。在默认配置的基础上,我做了一些修改,下面是我正在用的一个配置:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="{ &quot;compilerOptions&quot;: { &quot;module&quot;: &quot;es6&quot;, // 使用 ES2015 模块 &quot;target&quot;: &quot;es6&quot;, // 编译成 ES2015 (Babel 将做剩下的事情) &quot;allowSyntheticDefaultImports&quot;: true, // 看下面 &quot;baseUrl&quot;: &quot;src&quot;, // 可以相对这个目录 import 文件 &quot;sourceMap&quot;: true, // 使 TypeScript 生成 sourcemaps &quot;outDir&quot;: &quot;ts-build&quot;, // 构建输出目录 (因为我们大部分时间都在使用 Webpack,所以不太相关) &quot;jsx&quot;: &quot;preserve&quot;, // 开启 JSX 模式, 但是 &quot;preserve&quot; 告诉 TypeScript 不要转换它(我们将使用 Babel) &quot;strict&quot;: true, }, &quot;exclude&quot;: [ &quot;node_modules&quot; // 这个目录下的代码不会被 typescript 处理 ] }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript">{ <span class="hljs-string">"compilerOptions"</span>: { <span class="hljs-string">"module"</span>: <span class="hljs-string">"<a href="http://www.js-code.com/tag/es6" title="浏览关于“es6”的文章" target="_blank" class="tag_link">es6</a>"</span>, <span class="hljs-comment">// 使用 ES2015 模块</span> <span class="hljs-string">"target"</span>: <span class="hljs-string">"es6"</span>, <span class="hljs-comment">// 编译成 ES2015 (Babel 将做剩下的事情)</span> <span class="hljs-string">"<a href="http://www.js-code.com/tag/all" title="浏览关于“all”的文章" target="_blank" class="tag_link">all</a>owSyntheticDefault<a href="http://www.js-code.com/tag/import" title="浏览关于“Import”的文章" target="_blank" class="tag_link">Import</a>s"</span>: <span class="hljs-literal"><a href="http://www.js-code.com/tag/true" title="浏览关于“true”的文章" target="_blank" class="tag_link">true</a></span>, <span class="hljs-comment">// 看下面</span> <span class="hljs-string">"baseUrl"</span>: <span class="hljs-string">"src"</span>, <span class="hljs-comment">// 可以相对这个目录 import 文件</span> <span class="hljs-string">"source<a href="http://www.js-code.com/tag/map" title="浏览关于“Map”的文章" target="_blank" class="tag_link">Map</a>"</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// 使 TypeScript 生成 sourcemaps</span> <span class="hljs-string">"outDir"</span>: <span class="hljs-string">"ts-build"</span>, <span class="hljs-comment">// 构建输出目录 (因为我们大部分时间都在使用 Webpack,所以不太相关)</span> <span class="hljs-string">"jsx"</span>: <span class="hljs-string">"preserve"</span>, <span class="hljs-comment">// 开启 <a href="http://www.js-code.com/tag/jsx" title="浏览关于“JSX”的文章" target="_blank" class="tag_link">JSX</a> 模式, 但是 "preserve" 告诉 TypeScript 不要转换它(我们将使用 Babel)</span> <span class="hljs-string">"strict"</span>: <span class="hljs-literal">true</span>, }, <span class="hljs-string">"exclude"</span>: [ <span class="hljs-string">"node_modules"</span> <span class="hljs-comment">// 这个目录下的代码不会被 typescript 处理</span> ] }</code></pre> <h3 id="articleHeader1"><a href="http://www.js-code.com/tag/all" title="all" target="_blank">all</a>owSyntheticDefault<a href="http://www.js-code.com/tag/import" title="Import" target="_blank">Import</a>s</h3> <p>将这个属性的值设置为 <a href="http://www.js-code.com/tag/true" title="true" target="_blank">true</a>,它允许你使用 ES2015 默认的 <a href="http://www.js-code.com/tag/import" title="import" target="_blank">import</a>s 风格, 即使你导入的代码没有使用 ES2015 默认的 <a href="http://www.js-code.com/tag/export" title="export" target="_blank">export</a>。</p> <p>举个例子,当你 <a href="http://www.js-code.com/tag/import" title="import" target="_blank">import</a> 不是用 ES2015 编写的 <a href="http://www.js-code.com/tag/react" title="React" target="_blank">React</a> 时(虽然源码是,但是 <a href="http://www.js-code.com/tag/react" title="浏览关于“React”的文章" target="_blank" class="tag_link">React</a> 使用一个构建好的版本),就可以利用上面的属性设置。这意味着,严格意义上来讲,它没有使用 ES2015 默认的 <a href="http://www.js-code.com/tag/export" title="export" target="_blank">export</a>,所以当你使用 import 的时候, TypeScript 会警告你。尽管如此,像 Webpack 这样的构建工具能够导入正确的代码,所以我将这个属性设置为 <a href="http://www.js-code.com/tag/true" title="true" target="_blank">true</a>,相比使用 <code>import * as React from 'react'</code>,我更喜欢 <code>import React from 'react'</code> 这种方式。</p> <h3 id="articleHeader2">strict:true</h3> <p><a href="https://github.com/Microsoft/TypeScript/wiki/What" rel="nofollow noreferrer" target="_blank">TypeScript 2.3 版本</a>引入了一种新的配置选项,<code>strict</code>。当将这个值设置为 true 时,TypeScript 编译器会尽可能的严格 - 如果你将一些 JS 转为 TS,这可能不是你想要的,但是对于一些新的项目,使其尽可能的严格是有意义的。它还引入了一些不同的配置,其中几个比较重要的的有 <code>noImplicitAny</code> 和 <code>strictNullChecks</code>:</p> <h3 id="articleHeader3">noImplicitAny</h3> <p>将 TypeScript 引入一个现有的项目,当你不声明变量的类型时,TypeScript 不会抛出错误。但是,当我从零开始新建一个 TypeScript 项目,我希望编译器尽可能地严格。<br />TypeScript 默认做的一件事是将变量设置为 <code>any</code> 类型。<code>any</code> 是 TypeScript 中避免类型检查的有效手段,它可以是任何值。当你转换 JavaScript 时,使用 <code>any</code> 是很有用的,但是最好还是尽可能地严格。当将 noImplicitAny 设置为 true,你必须为变量设置类型。举个例子,当将 <code>noImplicitAny</code> 设置为 true 时,下面的代码会报错:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="function log(thing) { console.log('thing', thing) }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript"><span class="hljs-function"><span class="hljs-keyword"><a href="http://www.js-code.com/tag/function" title="浏览关于“function”的文章" target="_blank" class="tag_link">function</a></span> <span class="hljs-title">log</span>(<span class="hljs-params">thing</span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'thing'</span>, thing) }</code></pre> <p>如果你想了解更多关于 noImplicitAny 的信息,可以阅读 <a href="https://basarat.gitbooks.io/typescript/docs/options/noImplicitAny.html" rel="nofollow noreferrer" target="_blank">TypeScript Deep Dive</a></p> <h3 id="articleHeader4">strictNullChecks</h3> <p>这是另一个使 TypeScript 编译器更严格的选项。TypeScript Deep Dive 这本书<a href="https://basarat.gitbooks.io/typescript/docs/options/strictNullChecks.html" rel="nofollow noreferrer" target="_blank">有一个很好的章节介绍这个选项</a>。如果将这个选项设置为true,TypeScript 会更容易识别出你引用的一个可能是 <a href="http://www.js-code.com/tag/undefined" title="undefined" target="_blank">undefined</a> 值的地方,并将展示这个错误。例如:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="person.age.increment()" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript" style="word-break: break-word; white-space: initial;">person.age.increment()</code></pre> <p>当将 strictNullChecks 设置为 true,TypeScript 会认为 person 或者 person.age 可能是 <a href="http://www.js-code.com/tag/undefined" title="undefined" target="_blank">undefined</a>,它会报个错以确保你处理它。这会防止出现运行时错误,所以这看起来是一个从一开始就要打开的很棒的选项。</p> <h2 id="articleHeader5">配置 Webpack, Babel and TypeScript</h2> <p>我是 Webpack 的脑残粉;我喜欢它的插件生态系统、开发者工作流,喜欢它擅长管理复杂的应用和构建流程。所以,即使我们可能仅仅使用 TypeScript 编译器,我仍然喜欢引入 Webpack。因为 TypeScript 输出 React 和 <a href="http://www.js-code.com/tag/es6" title="es6" target="_blank">es6</a>(也就是 es2015,<a href="http://www.js-code.com/tag/babel" title="babel" target="_blank">babel</a> 把 <a href="http://www.js-code.com/tag/es6" title="es6" target="_blank">es6</a> 转成 <a href="http://www.js-code.com/tag/es5" title="es5" target="_blank">es5</a>,所以我们还需要 <a href="http://www.js-code.com/tag/babel" title="babel" target="_blank">babel</a>。让我们安装 Webpack,Babel 和相关的 p<a href="http://www.js-code.com/tag/reset" title="reset" target="_blank">reset</a>s 及 <a href="https://github.com/TypeStrong/ts-loader" rel="nofollow noreferrer" target="_blank">ts-loader</a>,ts-loader 是 TypeScript 在 Webpack 中的插件。</p> <p>还有 <a href="https://github.com/s-panferov/awesome-typescript-loader" rel="nofollow noreferrer" target="_blank">awesome-typescript-loader</a> ,也是 TypeScript 在 Webpack 中的插件,但是我首先找到的是 <code>ts-loader</code> 而且到目前为止它非常不错。如果谁使用了 <code>awesome-typescript-loader</code>,我很乐意看到关于它们两者的对比。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="yarn add webpack babel-core babel-loader babel-preset-es2015 babel-preset-react ts-loader webpack-dev-server" title="" data-original-title="复制"></span> </div> </p></div> <pre class="shell hljs"><code class="shell" style="word-break: break-word; white-space: initial;">yarn add webpack <a href="http://www.js-code.com/tag/babel" title="浏览关于“babel”的文章" target="_blank" class="tag_link">babel</a>-core babel-loader babel-p<a href="http://www.js-code.com/tag/reset" title="浏览关于“reset”的文章" target="_blank" class="tag_link">reset</a>-es2015 babel-preset-react ts-loader webpack-dev-server</code></pre> <p>此时此刻,我必须感谢 Tom Duncalf,他在博客中发表的 <a href="http://blog.tomduncalf.com/posts/setting-up-typescript-and-react/" rel="nofollow noreferrer" target="_blank">TypeScript 1.9 + React</a>,对我来说,是一个特别好的开始,我极力推荐它。</p> <p>在 Webpack 中没有特别的配置,但是我还是在代码中列出一些注释来解释它:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const webpack = require('webpack') const path = require('path') module.exports = { // 设置 sourcemaps 为 eval 模式,将模块封装到 eval 包裹起来 devtool: 'eval', // 我们应用的入口, 在 `src` 目录 (我们添加到下面的 resolve.modules): entry: [ 'index.tsx' ], // 配置 devServer 的输出目录和 publicPath output: { filename: 'app.js', publicPath: 'dist', path: path.resolve('dist') }, // 配置 devServer devServer: { port: 3000, historyApiFallback: true, inline: true, }, // 告诉 Webpack 加载 TypeScript 文件 resolve: { // 首先寻找模块中的 .ts(x) 文件, 然后是 .js 文件 extensions: ['.ts', '.tsx', '.js'], // 在模块中添加 src, 当你导入文件时,可以将 src 作为相关路径 modules: ['src', 'node_modules'], }, module: { loaders: [ // .ts(x) 文件应该首先经过 Typescript loader 的处理, 然后是 babel 的处理 { test: /.tsx?$/, loaders: ['babel-loader', 'ts-loader'], include: path.resolve('src') } ] }, }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript"><span class="hljs-keyword"><a href="http://www.js-code.com/tag/const" title="浏览关于“const”的文章" target="_blank" class="tag_link">const</a></span> webpack = <span class="hljs-built_in">require</span>(<span class="hljs-string">'webpack'</span>) <span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>) <span class="hljs-built_in">module</span>.<a href="http://www.js-code.com/tag/export" title="浏览关于“export”的文章" target="_blank" class="tag_link">export</a>s = { <span class="hljs-comment">// 设置 sourcemaps 为 <a href="http://www.js-code.com/tag/eval" title="浏览关于“eval”的文章" target="_blank" class="tag_link">eval</a> 模式,将模块封装到 eval 包裹起来</span> devtool: <span class="hljs-string">'eval'</span>, <span class="hljs-comment">// 我们应用的入口, 在 `src` 目录 (我们添加到下面的 resolve.modules):</span> en<a href="http://www.js-code.com/tag/try" title="浏览关于“try”的文章" target="_blank" class="tag_link">try</a>: [ <span class="hljs-string">'index.tsx'</span> ], <span class="hljs-comment">// 配置 devServer 的输出目录和 <a href="http://www.js-code.com/tag/public" title="浏览关于“public”的文章" target="_blank" class="tag_link">public</a>Path</span> output: { <span class="hljs-attr">file<a href="http://www.js-code.com/tag/name" title="浏览关于“name”的文章" target="_blank" class="tag_link">name</a></span>: <span class="hljs-string">'app.js'</span>, <span class="hljs-attr">publicPath</span>: <span class="hljs-string">'dist'</span>, <span class="hljs-attr">path</span>: path.resolve(<span class="hljs-string">'dist'</span>) }, <span class="hljs-comment">// 配置 devServer </span> devServer: { <span class="hljs-attr">port</span>: <span class="hljs-number">3000</span>, <span class="hljs-attr"><a href="http://www.js-code.com/tag/history" title="浏览关于“history”的文章" target="_blank" class="tag_link">history</a>ApiFallback</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">inline</span>: <span class="hljs-literal">true</span>, }, <span class="hljs-comment">// 告诉 Webpack 加载 TypeScript 文件</span> resolve: { <span class="hljs-comment">// 首先寻找模块中的 .ts(x) 文件, 然后是 .js 文件</span> extensions: [<span class="hljs-string">'.ts'</span>, <span class="hljs-string">'.tsx'</span>, <span class="hljs-string">'.js'</span>], <span class="hljs-comment">// 在模块中添加 src, 当你导入文件时,可以将 src 作为相关路径</span> modules: [<span class="hljs-string">'src'</span>, <span class="hljs-string">'node_modules'</span>], }, <span class="hljs-attr">module</span>: { <span class="hljs-attr">loaders</span>: [ <span class="hljs-comment">// .ts(x) 文件应该首先经过 Typescript loader 的处理, 然后是 babel 的处理</span> { <span class="hljs-attr">test</span>: <span class="hljs-regexp">/.tsx?$/</span>, <span class="hljs-attr">loaders</span>: [<span class="hljs-string">'babel-loader'</span>, <span class="hljs-string">'ts-loader'</span>], <span class="hljs-attr">include</span>: path.resolve(<span class="hljs-string">'src'</span>) } ] }, }</code></pre> <p>我们按照上面的方式配置 loaders ,从而使 <code>.ts(x)</code> 文件首先经过 <code>ts-loader</code> 的处理。按照 <code>tsconfig.json</code> 中的配置,使用 TypeScript 编译 <code>.ts(x)</code> 文件 - 输出 <code>ES2015</code>。然后,我们使用 Babel 将它降级到 ES5。为了实现这些,我创建了一个包含需要的 p<a href="http://www.js-code.com/tag/reset" title="reset" target="_blank">reset</a>s 的 <code>.babelrc</code> 文件:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="{ &quot;presets&quot;: [&quot;es2015&quot;, &quot;react&quot;] }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript">{ <span class="hljs-string">"presets"</span>: [<span class="hljs-string">"es2015"</span>, <span class="hljs-string">"react"</span>] }</code></pre> <p>现在我们已经做好了写 TypeScript 应用的准备。</p> <h2 id="articleHeader6">写一个 TypeScript React 组件</h2> <p>现在,我们准备好建立 <code>src/index.tsx</code>,这是我们这个应用的入口。我们可以创建一个虚拟的组件,渲染它,查看它是否正常运行。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="import React from 'react' import ReactDOM from 'react-dom' const App = () => {<br /> <a href="http://www.js-code.com/tag/return" title="return" target="_blank">return</a> (</p> <div> <p>Hello world!</p> </p></div> <p> )<br /> }</p> <p>React<a href="http://www.js-code.com/tag/dom" title="DOM" target="_blank">DOM</a>.render(<App ></App>, document.getElementById('app'))" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span> <span class="hljs-keyword">import</span> React<a href="http://www.js-code.com/tag/dom" title="浏览关于“DOM”的文章" target="_blank" class="tag_link">DOM</a> <span class="hljs-keyword">from</span> <span class="hljs-string">'react-<a href="http://www.js-code.com/tag/do" title="浏览关于“do”的文章" target="_blank" class="tag_link">do</a>m'</span> <span class="hljs-keyword">const</span> App = <span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> { <span class="hljs-keyword"><a href="http://www.js-code.com/tag/return" title="浏览关于“return”的文章" target="_blank" class="tag_link">return</a></span> ( <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name"><a href="http://www.js-code.com/tag/div" title="浏览关于“div”的文章" target="_blank" class="tag_link">div</a></span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Hello world!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span> ) } ReactDOM.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>, <a href="http://www.js-code.com/tag/document" title="浏览关于“document”的文章" target="_blank" class="tag_link">document</a>.getElementById('app'))</span></code></pre> <p>如果你运行 webpack,会看到下面的错误:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="ERROR in ./src/index.tsx (1,19): error TS2307: Cannot find module 'react'. ERROR in ./src/index.tsx (2,22): error TS2307: Cannot find module 'react-dom'." title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs groovy"><code>ERROR <span class="hljs-keyword">in</span> .<span class="hljs-regexp">/src/</span>index.tsx (<span class="hljs-number">1</span>,<span class="hljs-number">19</span>): error <span class="hljs-string">TS2307:</span> Cannot find module <span class="hljs-string">'react'</span>. ERROR <span class="hljs-keyword">in</span> .<span class="hljs-regexp">/src/</span>index.tsx (<span class="hljs-number">2</span>,<span class="hljs-number">22</span>): error <span class="hljs-string">TS2307:</span> Cannot find module <span class="hljs-string">'react-dom'</span>.</code></pre> <p>发生上面的错误是因为 TypeScript 试图确认 React 的类型、React 导出了什么。对于 React <a href="http://www.js-code.com/tag/dom" title="DOM" target="_blank">DOM</a>,TypeScript 会做同样的事情。React 并不是使用 TypeScript 编写的,所以它并没有包含那些信息。幸运地是,为了应对这种情况,社区已经创建了 <a href="https://github.com/DefinitelyTyped/DefinitelyTyped" rel="nofollow noreferrer" target="_blank">DefinitelyTyped</a>,这是一个大型的组件类型库。</p> <p>最近,安装机制改变了;所有的类型被发布到 npm @types scope 下。为了获得 React 和 ReactDOM 的类型,我们运行下面的命令:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="yarn add @types/react yarn add @types/react-dom" title="" data-original-title="复制"></span> </div> </p></div> <pre class="shell hljs"><code class="shell">yarn add @types/react yarn add @types/react-dom</code></pre> <p>通过上面的处理,错误不见了。无论何时,你安装一个依赖时,都应该试着安装 <code>@types</code> 包,或者你想查看是否有被支持的类型,你可以在 <a href="https://microsoft.github.io/TypeSearch/" rel="nofollow noreferrer" target="_blank">TypeSearch</a> 网站上查看。</p> <h2 id="articleHeader7">本地运行 app</h2> <p>为了在本地运行 app,我们只需要运行 <code>webpack-dev-server</code> 命令。我配置了一个脚本 <code>start</code>, 它能做上面的事情:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="&quot;scripts&quot;: { &quot;start&quot;: &quot;webpack-dev-server&quot; }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript"><span class="hljs-string">"scripts"</span>: { <span class="hljs-string">"start"</span>: <span class="hljs-string">"webpack-dev-server"</span> }</code></pre> <p>服务会找到 webpack.config.json 这个文件,使用它创建我们的应用。</p> <p>如果你运行 <code>yarn start</code> ,你会看到来自于 webpack-dev-server 的输出,包含 <code>ts-loader</code> 的输出,这些能够确认应用是否正常运行。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="$ webpack-dev-server Project is running at http://localhost:3000/ webpack output is served from /dist 404s will fallback to /index.html ts-loader: Using typescript@2.3.0 and /Users/jackfranklin/git/interactive-react-introduction/tsconfig.json Version: webpack 2.4.1 Time: 6077ms Asset Size Chunks Chunk Names app.js 1.14 MB 0 [emitted] [big] main webpack: Compiled successfully." title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs groovy"><code>$ webpack-dev-server Project is running at <span class="hljs-string">http:</span><span class="hljs-comment">//localhost:3000/</span> webpack output is served from /dist <span class="hljs-number">404</span>s will fallback to /index.html ts-<span class="hljs-string">loader:</span> Using typescript@<span class="hljs-number">2.3</span><span class="hljs-number">.0</span> and <span class="hljs-regexp">/Users/</span>jackfranklin<span class="hljs-regexp">/git/</span><a href="http://www.js-code.com/tag/int" title="浏览关于“int”的文章" target="_blank" class="tag_link">int</a>eractive-react-introduction/tsconfig.json <span class="hljs-string">Version:</span> webpack <span class="hljs-number">2.4</span><span class="hljs-number">.1</span> <span class="hljs-string">Time:</span> <span class="hljs-number">6077</span>ms Asset Size Chunks Chunk Names app.js <span class="hljs-number">1.14</span> MB <span class="hljs-number">0</span> [emitted] [big] main <span class="hljs-string">webpack:</span> Compiled successfully.</code></pre> <p>为了能够在本地看到效果,我创建了一个 index.html 文件,让它加载编译后的代码:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="<a href="http://www.js-code.com/tag/button" title="button" target="_blank">button</a>" <a href="http://www.js-code.com/tag/class" title="class" target="_blank">class</a>="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="top" target="_blank">top</a>" data-clipboard-<a href="http://www.js-code.com/tag/text" title="text" target="_blank">text</a>="<!DOCTYPE html><br /> <html lang=&quot;en&quot;><br /> <head><br /> <meta charset=&quot;UTF-8&quot;><br /> <title>My Typescript App</title><br /> </head><br /> <body></p> <div id=&quot;app&quot;></div> <p> <script src=&quot;dist/app.js&quot;></script><br /> </body>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="xml hljs"><code class="html"><span class="hljs-meta">&lt;!DOCTYPE html&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr"><a href="http://www.js-code.com/tag/char" title="浏览关于“char”的文章" target="_blank" class="tag_link">char</a>set</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My Typescript App<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"dist/app.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span></code></pre> <p>在端口 3000,我们将会看到 <code>Hello world!</code>,我们让 <code>TypeScript</code> 运行了!</p> <h2 id="articleHeader8">定义一个模块类型</h2> <p>在现在的工程中,我想使用 <a href="https://github.com/securingsincity/react-ace" rel="nofollow noreferrer" target="_blank">React Ace module</a> 包含一个代码编辑器。但是这个模块并不提供 types,并且也没有 <code>@types/react-ace</code>。在这种情况下,我们必须在应用中增加类型,这样可以使 TypeScript 知道如何去检查它的类型。这看起来非常烦人,让 TypeScript 至少知道所有第三方依赖关系的好处是,可以节省调试时间。</p> <p>定义一个只包含类型的文件,后缀是 <code>.d.ts</code>( ‘d‘ 代表 ‘declaration‘ ),你可以从 <a href="https://www.typescriptlang.org/docs/handbook/declaration-files/introduction" rel="nofollow noreferrer" target="_blank">TypeScript docs</a> 了解更多。在你的工程中,TypeScript 将会自动地找到这些文件,你不需要显式地导入它们。</p> <p>我创建了 <code>react-ace.d.ts</code> 文件,添加下面的代码,创建模块,定义它的默认 <a href="http://www.js-code.com/tag/export" title="export" target="_blank">export</a> 为一个 React 组件。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="<a href="http://www.js-code.com/tag/button" title="button" target="_blank">button</a>" <a href="http://www.js-code.com/tag/class" title="class" target="_blank">class</a>="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="top" target="_blank">top</a>" data-clipboard-<a href="http://www.js-code.com/tag/text" title="text" target="_blank">text</a>="declare module 'react-ace' {<br /> <a href="http://www.js-code.com/tag/int" title="int" target="_blank">int</a>erface ReactAce<a href="http://www.js-code.com/tag/prop" title="Prop" target="_blank">Prop</a>s {<br /> mode: string<br /> theme: string<br /> <a href="http://www.js-code.com/tag/name" title="name" target="_blank">name</a>: string<br /> editor<a href="http://www.js-code.com/tag/prop" title="Prop" target="_blank">Prop</a>s?: {}<br /> showPr<a href="http://www.js-code.com/tag/int" title="int" target="_blank">int</a>Margin?: <a href="http://www.js-code.com/tag/boolean" title="boolean" target="_blank">boolean</a><br /> minLines?: number<br /> maxLines?: number<br /> wrapEnabled?: <a href="http://www.js-code.com/tag/boolean" title="boolean" target="_blank">boolean</a><br /> value: string<br /> highlightActiveLine?: <a href="http://www.js-code.com/tag/boolean" title="浏览关于“boolean”的文章" target="_blank" class="tag_link">boolean</a><br /> width?: string<br /> fontSize?: number<br /> }</p> <p> <a href="http://www.js-code.com/tag/const" title="const" target="_blank">const</a> ReactAce: React.Component<a href="http://www.js-code.com/tag/class" title="Class" target="_blank">Class</a><ReactAceProps><br /> export = ReactAce<br /> }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript">declare <span class="hljs-built_in">module</span> <span class="hljs-string">'react-ace'</span> { <a href="http://www.js-code.com/tag/interface" title="浏览关于“interface”的文章" target="_blank" class="tag_link">interface</a> ReactAce<a href="http://www.js-code.com/tag/prop" title="浏览关于“Prop”的文章" target="_blank" class="tag_link">Prop</a>s { <span class="hljs-attr">mode</span>: string theme: string name: string editorProps?: {} showPrintMargin?: boolean minLines?: number maxLines?: number wrapEnabled?: boolean value: string highlightActiveLine?: boolean width?: string fontSize?: number } <span class="hljs-keyword">const</span> ReactAce: React.Component<a href="http://www.js-code.com/tag/class" title="浏览关于“Class”的文章" target="_blank" class="tag_link">Class</a>&lt;ReactAceProps&gt; <span class="hljs-keyword">export</span> = ReactAce }</code></pre> <p>我首先创建了一个 TypeScript 接口,这个接口包含组件的属性,<code><a href="http://www.js-code.com/tag/export" title="export" target="_blank">export</a> = ReactAce</code> 标明组件通过模块被导出。通过定义属性的类型,TypeScript 会告诉我是否弄错了属性的类型或者忘记设置一个类型,这是非常有价值的。</p> <h2 id="articleHeader9">测试</h2> <p>最后,使用 TypeScript,我也想有一个很好的测试方案。我是 Facebook 的 <a href="https://facebook.github.io/jest/" rel="nofollow noreferrer" target="_blank">Jest</a> 的超级粉丝,我在 google 上做了一些搜索,确认它是否能用 TypeScript 运行。结果发现,这是可行的,<a href="https://www.npmjs.com/package/ts-jest" rel="nofollow noreferrer" target="_blank"><code>ts-jest</code></a> 包可以做一些很重的转换。除此之外,还有一个做类型检查的 <code>@types/jest</code> 包,可以让你所有的测试都是类型确认过的。</p> <p>非常感谢 <code>RJ Zaworski</code>,他在博客上发表了 <a href="https://rjzaworski.com/2016/12/testing-typescript-with-jest" rel="nofollow noreferrer" target="_blank">TypeScript and Jest</a> ,这使我开始了解这个主题。如果你安装了 <code>ts-jest</code>,你只需要在 <code><a href="http://www.js-code.com/tag/package" title="package" target="_blank">package</a>.json</code> 中配置 Jest,下面是配置:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="<a href="http://www.js-code.com/tag/button" title="浏览关于“button”的文章" target="_blank" class="tag_link">button</a>" class="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="浏览关于“top”的文章" target="_blank" class="tag_link">top</a>" data-clipboard-<a href="http://www.js-code.com/tag/text" title="浏览关于“text”的文章" target="_blank" class="tag_link">text</a>="&quot;jest&quot;: {<br /> &quot;moduleFileExtensions&quot;: [<br /> &quot;ts&quot;,<br /> &quot;tsx&quot;,<br /> &quot;js&quot;<br /> ],<br /> &quot;trans<a href="http://www.js-code.com/tag/for" title="for" target="_blank">for</a>m&quot;: {<br /> &quot;\.(ts|tsx)$&quot;: &quot;<rootDir>/node_modules/ts-jest/preprocessor.js&quot;<br /> },<br /> &quot;testRegex&quot;: &quot;/*.spec.(ts|tsx|js)$&quot;<br /> }," title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript"><span class="hljs-string">"jest"</span>: { <span class="hljs-string">"moduleFileExtensions"</span>: [ <span class="hljs-string">"ts"</span>, <span class="hljs-string">"tsx"</span>, <span class="hljs-string">"js"</span> ], <span class="hljs-string">"trans<a href="http://www.js-code.com/tag/form" title="浏览关于“form”的文章" target="_blank" class="tag_link">form</a>"</span>: { <span class="hljs-string">"\.(ts|tsx)$"</span>: <span class="hljs-string">"&lt;rootDir&gt;/node_modules/ts-jest/preprocessor.js"</span> }, <span class="hljs-string">"testRegex"</span>: <span class="hljs-string">"/*.spec.(ts|tsx|js)$"</span> },</code></pre> <p>第一个配置告诉 Jest 寻找 <code>.ts</code> 和 <code>.tsx</code> 文件。 <code>trans<a href="http://www.js-code.com/tag/form" title="form" target="_blank">form</a></code> 对象告诉 Jest 通过 ts-jest 预处理器运行任何 TypeScript 文件,ts-jest 预处理器通过 TypeScript 编译器运行 TypeScript 文件,产出能让 Jest 识别的 JavaScript。最后,我更新了 <code>testRegex</code> 设置,目的是寻找任何 <code>*.spec.ts(x)</code> 文件,我更喜欢用这种方式命名转换。</p> <p>通过上面这些配置,我可以运行 <code>jest</code> 并且让每一件事情都如预期一样运行。</p> <h2 id="articleHeader10">使用 TSLint 规范代码</h2> <p>尽管 TypeScript 在代码中会给出很多检查提示,我仍然想要一个规范器,做些代码风格和质量检查。就像 JavaScript 的 ESLint,<a href="https://palantir.github.io/tslint/" rel="nofollow noreferrer" target="_blank">TSLint</a> 是检查 TypeScript 的最好选择。它和 ESlint 的工作方式相同 - 用一系列生效或不生效的规则,还有一个 <a href="https://github.com/palantir/tslint-react" rel="nofollow noreferrer" target="_blank">TSLint-React</a> 包增加 React 的具体规则。</p> <p>你可以通过 <code>tslint.json</code> 文件配置 TSLint,我的配置文件如下。我用 <code>tslint:latest</code> 和 <code>tslint-react</code> presets,它们可以使用很多规则。我不赞成一些默认设置,所以我重写了它们 - 你可以和我的配置不同 - 这完全取决于你!</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="{ &quot;defaultSeverity&quot;: &quot;error&quot;, &quot;extends&quot;: [&quot;tslint:latest&quot;, &quot;tslint-react&quot;], &quot;jsRules&quot;: {}, &quot;rules&quot;: { // 用单引号, 但是在 JSX 中,强制使用双引号 &quot;quotemark&quot;: [true, &quot;single&quot;, &quot;jsx-double&quot;], // 我更喜欢没有分号 翻译 | 开始使用 TypeScript 和 React-脚本宝典 &quot;semicolon&quot;: [true, &quot;never&quot;], // 这个规则使每个接口以 I 开头,这点我不喜欢 &quot;interface-name&quot;: [true, &quot;never-prefix&quot;], // 这个规则强制对象中的 key 按照字母顺序排列 &quot;object-literal-sort-keys&quot;: false }, &quot;rulesDirectory&quot;: [] }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript">{ <span class="hljs-string">"<a href="http://www.js-code.com/tag/default" title="浏览关于“default”的文章" target="_blank" class="tag_link">default</a>Severity"</span>: <span class="hljs-string">"error"</span>, <span class="hljs-string">"<a href="http://www.js-code.com/tag/extends" title="浏览关于“extends”的文章" target="_blank" class="tag_link">extends</a>"</span>: [<span class="hljs-string">"tslint:latest"</span>, <span class="hljs-string">"tslint-react"</span>], <span class="hljs-string">"jsRules"</span>: {}, <span class="hljs-string">"rules"</span>: { <span class="hljs-comment">// 用单引号, 但是在 JSX 中,强制使用双引号</span> <span class="hljs-string">"quotemark"</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">"single"</span>, <span class="hljs-string">"jsx-<a href="http://www.js-code.com/tag/double" title="浏览关于“double”的文章" target="_blank" class="tag_link">double</a>"</span>], <span class="hljs-comment">// 我更喜欢没有分号 :)</span> <span class="hljs-string">"semicolon"</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">"never"</span>], <span class="hljs-comment">// 这个规则使每个接口以 I 开头,这点我不喜欢</span> <span class="hljs-string">"interface-name"</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">"never-prefix"</span>], <span class="hljs-comment">// 这个规则强制对象中的 key 按照字母顺序排列 </span> <span class="hljs-string">"object-literal-sort-keys"</span>: <span class="hljs-literal"><a href="http://www.js-code.com/tag/false" title="浏览关于“false”的文章" target="_blank" class="tag_link">false</a></span> }, <span class="hljs-string">"rulesDirectory"</span>: [] }</code></pre> <p>我可以运行 <code>tslint --project tsconfig.json</code> 规范我的项目</p> <h2 id="articleHeader11">结论</h2> <p>总之,到目前为止,用 TypeScript 开发我很高兴。我肯定会发表更多博文来描述这门语言的细节和我是如何使用 TypeScript 的。但仅就如下操作而言,构建过程、配置所有的工具、开始使用类型,这真是一种享受。如果你正在将你的 JS 应用结构化,想要一个更强大的编译器避免错误并减少调试时间,我极力推荐你尝试 TypeScript。</p> <p>如果你想看源码或者以本文中的例子作为开始,我<a href="https://github.com/javascript-playground/react-typescript-jest-demo" rel="nofollow noreferrer" target="_blank">在 GitHub 上放了一个例子</a>,如果你有任何问题,可以提 issue。</p> <p><span class="img-wrap"><img data-src="/img/remote/1460000010887896" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="" title="" style="cursor: pointer;"></span></p> <p><span class="img-wrap"><img data-src="/img/remote/1460000011128647" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="" title="" style="cursor: pointer;"></span></p> <blockquote> <p>iKcamp原创新书《移动Web前端高效开发实战》已在亚马逊、京东、当当开售。</p> </blockquote> <p></code></p>

总结

以上是脚本宝典为你收集整理的

翻译 | 开始使用 TypeScript 和 React

全部内容,希望文章能够帮你解决

翻译 | 开始使用 TypeScript 和 React

所遇到的程序开发问题,欢迎加入QQ群277859234一起讨论学习。如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典网站推荐给程序员好友。 本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。

80%的人都看过