SegmentFault Midqiu最新的文章
2022-12-05T09:02:00+08:00
https://segmentfault.com/feeds/blogs
https://creativecommons.org/licenses/by-nc-nd/4.0/
typescript 在 nodejs开发中的使用
https://segmentfault.com/a/1190000042973163
2022-12-05T09:02:00+08:00
2022-12-05T09:02:00+08:00
Midqiu
https://segmentfault.com/u/midqiu
0
<blockquote>注:本文的面向读者,假设你已经对typescript和nodejs有了初步的了解了:知道如何安装npm 包,如何运行node代码,以及tsc是做什么的。</blockquote><h2>代码提示</h2><p>安装<code>@types/node</code>库文件,编写代码的时候,编辑器才会智能提示。</p><pre><code>npm install @types/node -D</code></pre><p>效果:<br><img src="/img/bVc4sZw" alt="image.png" title="image.png"></p><p>此时,编辑器还是会提示一些浏览器环境的api,如<code>window</code>对象。<br><img src="/img/bVc4sZB" alt="image.png" title="image.png"><br>这是因为<code>tsconfig.json</code>配置文件中的<code>compilerOptions.lib</code>的默认值包含了<code>DOM</code>的库。按需配置需要的lib 即可覆盖默认值。(库列表详见这里<a href="https://link.segmentfault.com/?enc=FvmX9tlJNykP2iEcams%2BhA%3D%3D.blv5M%2BodcKpwlrE%2FXUTnnDFifv0Ov8akyFbDXn1WbhzZ2OhrIlOI1Nq8A5s6bLNZ" rel="nofollow">https://www.typescriptlang.or...</a>)</p><pre><code class="json">{
"compilerOptions": {
"lib": ["ES6"]
}
}
</code></pre><h3>expressjs</h3><p>因为本人主要使用express,express的用法看官方文档,这里只列出了 typescript和express 搭配使用的一些细节。</p><p><code>npm install @types/express -D</code> 安装express的接口描述文件。</p><p>原来js中<code>commonjs</code>的写法:</p><pre><code class="javascript">const express=require("express")
const app=express()</code></pre><p>转换成在 ts 中<code>esm</code>的写法:</p><pre><code class="typescript">import * as express from "express"
const app = express()</code></pre><h4>express-session</h4><p>我的express项目中使用 express-session 来实现用户登录态的功能。<br>具体这个库的使用方法看这个库的<a href="https://link.segmentfault.com/?enc=%2B4jiNIrMLFhE8VL8qXbYfQ%3D%3D.%2FFKGv4I4civJ89XPaQ4i5%2B9bcjOWhGS0BzbNjAn9pIaoGrqLtnCwfvVnsLtJ3wH%2B" rel="nofollow">官方文档</a>就行了,这里主要展示和ts的相关用法。</p><h5>安装库的描述文件:</h5><pre><code>npm install @types/express-session -D</code></pre><h5>使用:</h5><p>文档给的引入用法是这样的:</p><pre><code class="javascript">var session = require('express-session')</code></pre><p>那么对应的esm用法是这样的:</p><pre><code class="typescript">import * as session from 'express-session'</code></pre><p><img src="/img/bVc4s88" alt="image.png" title="image.png"></p><p><img src="/img/bVc4s96" alt="image.png" title="image.png"><br>按照官方的文档的例子,用户登录后,将用户信息绑定到<code>req.session</code>的<code>user</code>属性上了,在ts中使用会提示这个错误,<br><img src="/img/bVc4taa" alt="image.png" title="image.png"><br>这时需要我们告诉编辑器/编译器,req.session上有这个属性。</p><p>在项目增加<code>types.d.ts</code>文件,内容如下:</p><pre><code class="typescript">import "express-session"
declare module "express-session" {
interface SessionData {
user: {name:string,age:number} //给 req.session.user
}
}</code></pre><p>这样就能正常使用了。</p><h2>debug 调试</h2><ol><li><p>设置 <code>tsconfig.json</code>文件中的<code>compilerOptions.sourceMap</code>为<code>true</code>:</p><pre><code class="json">{
"compilerOptions": {
……
"sourceMap": true,
"lib": ["ES6"],
……
}
}</code></pre></li><li><p>创建<code>.vscode/launch.json</code>文件,内容如下:</p><pre><code class="json">{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动程序",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/src/app.ts",
"outFiles": [
"${workspaceFolder}/**/*.js"
]
}
]
}</code></pre><p>注意其中的 program 支持以 <code>.ts</code>文件;</p></li><li><code>npx tsc -w</code> 编译代码(我一般习惯手动执行,也可以参考文档配置debug之前自动执行tsc 任务)</li><li>按F5启动调试模式,或点击菜单中的【运行】-【启动调试】调试功能。<br>详见VSCode 的文档<a href="https://link.segmentfault.com/?enc=MVTcUbIvD613XjZ03agyUQ%3D%3D.6t%2BUgLD509mR6yisptLEd820Hq9bxWvQFZV%2FSrKNNWDvljpRO2ns5d1BlxyiTFJSsnqBLTaL4i62ZM7wj5fu9qWz8GkbK%2F0DOQqTSawDsHE%3D" rel="nofollow">https://code.visualstudio.com...</a> 。</li></ol><h2>运行</h2><p>当我们运行 nodejs 代码的时候,执行的是编译后的代码,这时候如果代码里面报错希望提示在源码里的位置,可以通过<code>--enable-source-maps</code>,启动服务:</p><pre><code>node --enable-source-maps dist/app.js</code></pre><p>效果如下:<br><img src="/img/bVc4twN" alt="image.png" title="image.png"></p><p>这种方式不需要改代码,好于我之前写的<a href="https://segmentfault.com/a/1190000007183406">这篇文章</a>里面的方式。</p><h2>常见问题</h2><h3>typescript 版本</h3><p>早期我习惯是 <code>npm install typescript -g</code> 全局安装typescript。<br>有时候不同项目使用的typescript 版本不一样,所以更好的方式是执行<code>npm install typescript</code> 安装到项目里,每个项目自己安装自己对应的ts版本。然后通过<code>npx tsc</code>调用项目内的typescript 编译代码。</p><p>此外,VSCode 默认使用VSCode自带的typescript进行代码解析,如果自带的版本和项目内使用版本不一样,有时候编辑器会提示语法错误(常出现在VSCode 自带的版本高于项目内使用的版本且tsconfig.json 中配置了<code>strict</code>模式时),可以通过如下操作,让编辑器使用项目内的typescript进行解析服务。</p><blockquote>打开任一ts文件,点击右下角的 typescript 左边的<code>{}</code>,然后在悬浮窗里点击<code>Select Version</code><br><img src="/img/bVc4s3j" alt="image.png" title="image.png"><br>再选择 <code>Use Workspace Version</code>:<br><img src="/img/bVc4s3m" alt="image.png" title="image.png"></blockquote><h3>windows 系统下,文件名大小写的问题</h3><p>在windows 操作系统中,文件名是不区分大小写的,当a.ts 文件编译成a.js文件后,这时候我们修改了ts文件名,将a.ts改成了A.ts,那么windows不会重新编译出一个A.js文件,还是复用原来的a.js文件,所以这时候运行代码的时候就会,提示找不到A.js文件,解决办法是将a.js文件手动删除掉,并触发tsc编译。</p>
使用 github 和 Deno Deploy 搭建一个博客网站
https://segmentfault.com/a/1190000042857780
2022-11-21T17:34:46+08:00
2022-11-21T17:34:46+08:00
Midqiu
https://segmentfault.com/u/midqiu
0
<p>这个可能是目前最简单的搭建博客网站的方式了。你只需要有一个github账号就行了。本博客一切从简,直接用github的在线编辑功能,不需要本地安装Nodejs/Deno、git客户端、然后再配置git的代理,配置代码仓库地址,本地再下载安装编辑器、克隆代码到本地……</p><blockquote><p><del>github 是一个用来放代码的网站,程序员大多使用此网站存放自己的代码,和别人交流自己/别人的代码的bug……</del></p><p>Deno Deploy 是一个服务部署网站,你把代码交给它,它就会把你的代码跑起来了。类似于腾讯云、阿里云之类的,比他们更简单更易用,不用再自己买机器装系统blabla等繁琐的操作了。只不过是只能部署用Deno (javascript & typescript)写的服务。可以使用 github 的账号登录。部署在Deno Deploy的服务,会部署到全球34个地区,确保在世界范围内的人都能快速的访问到 Deno Deploy 上部署的服务。</p></blockquote><p>效果展示:<a href="https://link.segmentfault.com/?enc=n0jPzTdckgr%2FR0r0cTcR8A%3D%3D.eiMd8a%2FDS7UUU%2FA4AIMFUrx4mwTb5y3JBw6Rc2FUA7M%3D" rel="nofollow">https://midqiu.deno.dev/</a></p><p>简单概括一下步骤:</p><ol><li>在 github 上创建一个代码仓库,用来存放博客系统的代码和内容。</li><li>在 Deno Deploy 平台上创建一个项目,关联上一步的代码仓库。</li><li>在github上编写博客内容,推送到github仓库后,等个10s左右,Deno Deploy 会自动部署完成。</li></ol><h2>创建 github 仓库,存放博客代码和内容</h2><h3>0. 创建代码仓库,可以选择私有的或公开</h3><p><img src="/img/bVc3Zoi" alt="image.png" title="image.png"><br>项目按照你的需要填你自己起的名字。<br>可以选择<code>Private</code>,也可以选<code>Public</code>,选择<code>Public</code>的话,别人就能看到你的代码仓库里面的内容,注意不要放些敏感内容。<br><img src="/img/bVc4ttY" alt="image.png" title="image.png"><br>勾上这个 Add a README file,初始化代码仓库,否则需要在本地用git命令工具初始化,就麻烦了。</p><blockquote>一个小技巧:在github 的仓库主页,按句号<code>.</code>对应的按键,可以用github的在线编辑器打开此仓库,可以直接在线编辑提交到代码仓库。<br><img src="/img/bVc3Zpf" alt="image.png" title="image.png"></blockquote><h3>1. 配置博客相关信息</h3><p>在项目根目录下创建一个名为<code>main.tsx</code>的文件,文件内容如下(根据需要改成你的相关信息):</p><pre><code class="typescript">import blog from "https://deno.land/x/blog/blog.tsx";
blog({
author: "Dino",
title: "My Blog",
description: "The blog description.",
avatar: "https://deno-avatar.deno.dev/avatar/83a531.svg",
avatarClass: "rounded-full",
links: [
{ title: "Email", url: "mailto:bot@deno.com" },
{ title: "GitHub", url: "https://github.com/denobot" },
{ title: "Twitter", url: "https://twitter.com/denobot" },
],
lang: "zh",
});
</code></pre><p>更多详细设置,看 <a href="https://link.segmentfault.com/?enc=c7hw770geZxEnefXE2ZckA%3D%3D.%2FVHvZI45BevJWEV1Yf89ZhTnjY3bR%2FuSP%2ByCQWmIf1A%3D" rel="nofollow">deno_blog 文档</a></p><h3>2. 创建博客内容</h3><p>创建文件夹<code>posts</code>,注意,这个文件夹名字固定是这个;然后在文件夹中创建第一篇博客,比如这里创建了一个名为<code>hello_world.md</code>,的文件作为第一篇博客(注意:文件名称不要有空格和中文),内容如下:</p><pre><code class="markdown">---
title: 第一篇博客
publish_date: 2022-11-20
tags: ['hello-world']
---
这是我的第一篇博客!这里是博客内容
</code></pre><p>将内容推送到 github 的代码仓库中。</p><h2>在Deno Deploy 平台创建项目,并绑定github 上的仓库</h2><ol><li>打开<a href="https://link.segmentfault.com/?enc=RTiQS%2FX6CUCiQLW8DH0AFw%3D%3D.M3GPBWH9GhLxBeEX%2F1K%2BHYYepwla%2FCdqRyAB4nFgEho%3D" rel="nofollow">https://deno.dev</a>,使用github账号登录。</li><li>进入到管理台,点击 New Project 按钮创建新的项目。<br><img src="/img/bVc3Zpl" alt="image.png" title="image.png"></li><li>依次选择,对应的代码仓库-分支-构建方式(Automatic)-入口文件(main.tsx),并设置<strong>name</strong>,然后点击 <code>Link</code>按钮创建项目。<br><img src="/img/bVc3ZqQ" alt="image.png" title="image.png"></li></ol><blockquote>注意:如果<strong>name</strong>是aaa,那么最终的博客的访问域名是 <code>https://aaa.deno.dev</code>;可以到设置里面修改。当然你可以在设置中配置绑定自己的域名如 aaa.com 等。这里就不做说明了。</blockquote><p><img src="/img/bVc3Zpy" alt="image.png" title="image.png"></p><h2>更新、新增博客</h2><p>在<code>posts</code>文件下,新增一篇<code>.md</code>结尾的文件,内容格式参考上面的例子。(我们这个博客系统会自动扫描<code>posts</code>文件夹里面的md文件解析成博客内容的。)</p><p>更新博客的话,就修改相应的 <code>.md</code>文件的内容。</p><p>然后将改动推送到github 的代码仓库里,等个十几秒,Deno Deploy会自动构建成功,刷新博客地址就能看到新的内容了。</p><h2>其他</h2><p>下面是网站在国内的测速:<br><img src="/img/bVc3Zry" alt="image.png" title="image.png"></p><p>此教程使用的 Deno 官方出的 blog 库,优点是简单,默认主题简洁好看。此外,Deno官方还写了一篇如何将 <del>最</del>流行的博客系统 <code>Hugo</code> 部署到Deno Deploy上的文章,<code>Hugo</code>功能更强大一些,不过部署起来要稍微麻烦一点,感兴趣的可以看<a href="https://link.segmentfault.com/?enc=iDexpxPxVdnQ7U7P%2BQKxqQ%3D%3D.MfTBdZ9GBgS0DcsnXUFMudomAKDivl61d%2FKOhhtVpobnnoUzN7Ls%2FXoNTuvpY8Jm90mMGo6meWz%2FqaLxwv9vjQ%3D%3D" rel="nofollow">这里</a></p>
JSDoc 快速上手
https://segmentfault.com/a/1190000040308360
2021-07-07T17:15:50+08:00
2021-07-07T17:15:50+08:00
Midqiu
https://segmentfault.com/u/midqiu
12
<p>JSDoc 是在JS代码的注释里,以特定的格式标记变量的类型,函数的参数、返回值等,这样做可以避免调用函数的时候传错或少传参数,提高代码的健壮性,减少bug;再加上编辑器的支持,可以极大的提高编码的效率。</p><p>比如说下面的这个例子,<br><img src="/img/bVcTfXx" alt="image.png" title="image.png"><br>因为我们标记了<code>pd</code>的类型,当调用<code>pd</code>这个变量的时候,编辑器可以非常方便的提示这个对象上有什么方法。</p><p>我们翻看JSDoc的官方文档发现罗列了一大堆的功能,但其实常用的功能也就几个,只需要花几分钟掌握一下下面的几个使用方法,就可以大幅度提高写代码的编辑体验。</p><p>JSDoc语法上要求以<code>/**</code>开头,<code>*/</code>的注释。</p><h2>声明<code>函数的参数</code>的类型</h2><pre><code>@param {参数的类型} 参数的名 注释</code></pre><p><img src="/img/bVcTghc" alt="" title=""></p><p>如图所示,当我们定义好一个函数后,在函数的上方输入 <code>/**</code>然后按回车,编辑器会自动替我们补充好相关的变量名等信息,我们只需要填上参数的类型就可以了。</p><p>写好类型之后,在函数内部使用,编辑器会提示对应的方法和属性;</p><p><img src="/img/bVcTh1M" alt="image.png" title="image.png"></p><p>调用函数的时候,编辑器也会解析我们写到JSDoc内容,提示需要传入的参数的类型和参数的注释。<br><img src="/img/bVcTh1Q" alt="image.png" title="image.png"></p><p><code>类型</code>除了图上所示的<code>string</code>之外,还有<code>boolean</code>、 <code>undefined</code>、 <code>null</code> 类型;还有复杂类型,<code>{key1:string,key2?:number}</code> ;还可以相互组合比如 <code>string|number </code> 等typescript里面可以用<code>type</code>定义的。</p><h2>声明<code>函数的返回值</code>的类型</h2><p>用<code>@returns</code>来指定函数的参数类型和返回值类型</p><pre><code>@returns {string}</code></pre><p>例如:</p><pre><code>/**
*
* @param {string} id 注释注释注释
* @param {string} name 注释注释注释
* @returns {string}
*/
function getName(id, name) {
//name.
}</code></pre><p>调用的效果:<br><img src="/img/bVcTh3F" alt="image.png" title="image.png"></p><h2>声明变量的类型</h2><pre><code class="javascript">/**@type {string} */
var aaa=global.aaa</code></pre><p>效果图:<br><img src="/img/bVcTfKo" alt="image.png" title="image.png"></p><h2>定义一个类型</h2><p>有时候,有一些类型比较复杂,并且许多地方都需要用,这时候我们可以定义一个<code>类型</code>,供其他地方使用。</p><pre><code>@typedef {类型} 类型名</code></pre><p>比如,我们定义了一个类型User,分别有两个属性name和age</p><pre><code>/**@typedef {{name:string,age:number}} User */</code></pre><p>也可以写成这种方式:</p><pre><code>/**
* @typedef {Object} User
* @property {string} name
* @property {number} age
*/</code></pre><p>在函数定义中使用:<br><img src="/img/bVcTh8c" alt="image.png" title="image.png"></p><p>在其他地方使用:<br><img src="/img/bVcTh7M" alt="image.png" title="image.png"></p><h3>定义一个函数类型的复杂类型:</h3><pre><code>/**@typedef {(a:string,b:string)=>void} FN */</code></pre><p>其他例子,比如标记对象的某个属性比如说<code>get</code>是一个函数,要标准这个函数里面参数的类型:<br><img src="/img/bVcTkf6" alt="image.png" title="image.png"></p><p>或者这样:<br><img src="/img/bVcTkgG" alt="image.png" title="image.png"></p>
写给JS程序员的typescript入门教程(一)
https://segmentfault.com/a/1190000020940503
2019-11-07T22:50:45+08:00
2019-11-07T22:50:45+08:00
Midqiu
https://segmentfault.com/u/midqiu
14
<h2>为什么要用 typescript</h2>
<p>typescript引入了<code>类型</code>,避免了诸如函数调用传错参数的低级错误:</p>
<p><img src="/img/bVbwtX6" alt="clipboard.png" title="clipboard.png"></p>
<p><img src="/img/bVbyXgF" alt="clipboard.png" title="clipboard.png"></p>
<p>提供了代码提示:<br><img src="/img/bVbwtYa" alt="clipboard.png" title="clipboard.png"></p>
<h2>如何使用</h2>
<pre><code>npm install typescript -g</code></pre>
<p>这里需要说明一下的是,<code>typescript</code>是一个泛指,包括语言特性和语言相关的生态功能。要不然看官方的更新文档,就会有困惑,有很多明显不属于typescript<strong>语言</strong>的更新,比如重命名的时候对应的函数或文件跟着自动变了这种功能,很明显不属于语言的特性,应该是编辑器或者IDE负责的东西,咋就放到语言的更新日志里了呢?</p>
<h2>从一个例子说起</h2>
<p>来,我们看个例子:</p>
<pre><code class="typescript">function add(a:number, b:number):number {
return a+b
}</code></pre>
<p>上面的代码,我们声明了一个<code>add</code>函数,接收两个参数a和b,告诉编辑器和调用add函数的人,“这俩参数都是number类型,别传错参数啊,对了,我这个函数的返回值也是一个number类型,别指望我给你返回其他东西”。</p>
<p>我们可以看出,和JS最大的区别就是,增加了类型。</p>
<h2>类型可以用在哪里</h2>
<p>我们上面的例子里,<code>类型</code>用来标注函数的参数的类型、函数的返回值类型。此外也可以用来表示一个变量的类型。<br>比如:</p>
<pre><code>var a:number=1</code></pre>
<p>上面的代码的意思是,声明里一个变量a,这个变量a的类型是number类型。由于typescript的<code>类型推断</code>功能,我们上面的代码也可以写成这样:</p>
<pre><code>var a=1</code></pre>
<p>ts编译器看到后面的数字1之后,会智能的推断的出a是一个number类型,是不是发现ts还是很聪明的嘛</p>
<p><img src="/img/bVbzSi1" alt="image.png" title="image.png"></p>
<h2>都有哪些类型</h2>
<h3>常用类型</h3>
<p>除了我们上面说的number类型,还有这几个<strong>常用</strong>类型:string boolean undefined null 。<br>当然了复杂类型也是有的,</p>
<pre><code>var list:string[]=[] </code></pre>
<p>表示的是变量list是一个数组,这个数组里面每个元素都是string。</p>
<h4>对象</h4>
<pre><code class="typescript">function f1(a: { name: string; age: number }) {
}</code></pre>
<p>上面的代码,表示参数a是一个<code>对象</code>,这个对象上有name和age两个属性,并且这两个属性的类型分别是string和number,那么当我们调用这个函数的时候,就要出符合条件的参数,不符合的话,ts就提示代码写的有问题了。<br><img src="/img/bVbzSla" alt="image.png" title="image.png"></p>
<p>我们也可以用<code>interface</code>来声明一个对象结构,</p>
<pre><code>interface af {
name: string
age: number
}
function f1(a:af) {
}</code></pre>
<p>和Java的interface有点像但不太一样,我们把它理解成用来声明一个<code>结构</code>,这个结构长成这个样子:有属性xxx,对应的值是string类型,有属性yyy,对应的值的类型是number……</p>
<p>有个注意的点是,当我们传入的参数多了一些的属性的话,ts也会提示报错:<br><img src="/img/bVbz1BJ" alt="image.png" title="image.png"><br>那么要解决这种情况,一种方式是改造我们的interface成这样子:</p>
<pre><code>interface af {
name: string
age: number
[attr:string]:any
}</code></pre>
<p>多出来的<code>[attr:string]:any</code>意思是说我这个af上,还可能有一些其他的属性,对应的属性值的类型是any。<br>同样的,当我们往a上面赋值一些新的属性的时候,也会提示,<br><img src="/img/bVbz1C9" alt="image.png" title="image.png"><br>我们也要加<code>[attr:string]:any</code>。</p>
<p>另外一种方法参看文章后面的类型断言。</p>
<h4>函数类型</h4>
<p><img src="/img/bVbzSmx" alt="image.png" title="image.png"><br>现在,我们这里有个参数callback,它是一个函数类型,那怎么声明呢:<br><img src="/img/bVbzSmI" alt="image.png" title="image.png"><br>其中void表示这个函数没有返回值。那通常,我们的回调函数会需要一些参数来接受数据:<br><img src="/img/bVbzSmR" alt="image.png" title="image.png"></p>
<p>当然我们也可以把这个callback的类型给提取出来,用interface声明一个函数类型(是的,你没看错……就是刚才用来声明对象的interface,目前你知道了它有两个作用了)</p>
<pre><code class="typescript">interface ccc{
(data:string):void
}
function getInfo(id:number,callback:ccc){
}</code></pre>
<p>注意写法有点稍微不一样,一个是<code>=>void</code> 一个是<code>:void</code></p>
<h4>字面量类型</h4>
<p><img src="/img/bVbzSno" alt="image.png" title="image.png"></p>
<p><img src="/img/bVbzSnB" alt="image.png" title="image.png"><br>上面,a3和a4就只能是固定的字面量<code>"name"</code>或者<code>1</code>了。</p>
<p>还有个any类型,顾名思义,表示任意类型,是其他类型的子类型。<br><img src="/img/bVbzSlw" alt="image.png" title="image.png"><br>你看,本来f2是要传一个number进来的,我们传了一个any类型进去也不报错,一般是,当我们不指明变量(常量、参数、返回值)类型,ts又推断不出来的时候,ts会推断成any类型。(这个需要到tsconfig.json里面配置)</p>
<h3>类型之间运算</h3>
<p>用<code>|</code>表示或的意思:<br><img src="/img/bVbzSpx" alt="image.png" title="image.png"><br>比如这里,我们告诉编译器,u1这个变量可能是1也可能是2,也可能是3。<br>再比如:</p>
<pre><code>var u2:"aaaa"|1|{a:string}</code></pre>
<p>可能是三种完全不同的类型。<br>用<code>&</code>表示合并两个类型:<br><img src="/img/bVbzSqp" alt="image.png" title="image.png"><br>这样,u1就有a和b加一块的属性了。</p>
<h3>声明一个类型</h3>
<p>使用<code>type</code>来声明一个类型,比如说,上面的一长串<code>"aaaa"|1|{a:string}</code>我们再很多地方都要用到,我们可以提取出来,起个名字供大家调用:</p>
<pre><code>type uu="aaaa"|1|{a:string}
var u3:uu
...
var u4:uu
interface a {
aaa: string
}
interface fc {
(data: string): void
}
type uu2 = a & fc
</code></pre>
<h2>类型断言</h2>
<p>啥是类型断言呢,顾名思义,就是对类型的判断。比如我们上面举的一个例子:当传进来的参数不符合要求时,<br><img src="/img/bVbz1Dg" alt="image.png" title="image.png"></p>
<p>使用as语句,告诉编译器/编辑器,“你就把我传进来的参数当成符合af接口的数据吧”,相当于我人肉判断了,我传的参数类型我知道符合条件。<br>再比如:声明变量的时候:<br><img src="/img/bVbz1Dm" alt="image.png" title="image.png"></p>
<h3>非空断言</h3>
<p>有一种情况,如下,当我们在tsconfig.json里面开启了严格的null检查的时候,<br><img src="/img/bVbz1HL" alt="image.png" title="image.png"><br>这时候,当然我们 使用as string就可以搞定,其实还有个小技巧,使用<code>!</code>告诉ts这个变量不是null也不是undefined<br><img src="/img/bVbz1H1" alt="image.png" title="image.png"></p>
<h2>类型保护</h2>
<p>说白了就是当我们使用一个变量的时候,当访问到可能不存在的属性或方法的时候,强制要求做类型判断:</p>
<h3>使用typeof</h3>
<p>比如这个例子:<br><img src="/img/bVbz1DQ" alt="image.png" title="image.png"><br>参数a可能是number或者string,默认情况下,只能调用number和string都有的方法。当调用number独有的方法比如说toFixed的时候就报错了。这时候你就应该判断一下,如果是number类型的再调用toFixed<br><img src="/img/bVbz1D6" alt="image.png" title="image.png"><br>上面的例子,你会发现,ts还是挺智能的,自动推断出else的情况就是string类型。</p>
<h3>使用 instanceof</h3>
<p><img src="/img/bVbz1Fb" alt="image.png" title="image.png"><br>instanceof 差不多,主要用来判断是不是一个类的对象。</p>
<h3>使用 in</h3>
<p>你可能会机智的想到了,那假如类型是interface呢,js里面可没有这东西<br><img src="/img/bVbz1Fk" alt="image.png" title="image.png"></p>
<p>ts也做了非常聪明的推断,就不详细说了。</p>
<h2>泛型</h2>
<p>有时候,我们的几个类型非常相似,只有一两个参数不一样,比如常在CMS开发中定义接口返回值类型的情况,如下面的UserResponse和RoleResponse</p>
<pre><code>interface User{
name: string
age:number
}
interface Role{
name: string
id:string
}
interface UserResponse{
ret: number
message:string
data:User
}
interface RoleResponse{
ret: number
message:string
data:Role
}
</code></pre>
<p>这时候我们就在想能不能把公共的部分提前出来作为一个通用的类型,然后这个通用的类型接收不同的参数并生成新的类型?当然是可以的:</p>
<pre><code>interface CommonResponse<T>{
ret: number
message: string
data: T
}
type UserResponse = CommonResponse<User>
type RoleResponse=CommonResponse<Role></code></pre>
<p>你会发现泛型有点类似于函数参数。</p>
<h3>泛型默认值</h3>
<p>和函数参数一样,我们也可以给泛型设置个默认值,当不传的时候就使用默认值。</p>
<pre><code>interface T1<T = any>{
aaa: string
t:T
}</code></pre>
<h3>多个泛型</h3>
<p>也支持多个泛型,</p>
<pre><code>interface T1<T ,K> {
aaa: string
t: T
k:K
}</code></pre>
<h3>泛型约束 extends</h3>
<p>有时候,我们想要约束一下传进来的泛型的类型:<br>使用extends来约束<br><img src="/img/bVbz1Gi" alt="image.png" title="image.png"></p>
<p>泛型除了可以用在interface上,还可以用在type、class、function上:</p>
<pre><code>type t1<T> = {
aaa: T
}
type t2<T> = string | T
class C<T> {
aaa: T
constructor() {}
}
function get<T>(a:T) :T{
return a
}
var g = get<string>("")
</code></pre>
<p>这里说一个特别常用的例子:Promise,<br><img src="/img/bVbz1Hp" alt="image.png" title="image.png"><br>不加泛型的时候,ts不知道await get()的返回值是什么类型,加了泛型之后就知道了,并且能智能提示了:<br><img src="/img/bVbz1Ho" alt="image.png" title="image.png"></p>
<h2>tsconfig.json</h2>
<p>本质上,我们写的ts代码最终会编译js代码,比如删除掉ts代码里面的类型接口等。那么这个编译行为有许多参数可以控制,最常用的方法是在项目根目录创建一个tsconfig.json的文件,ts编译代码的时候会根据里面的配置进行编译。</p>
<p>通过命令行执行<code>tsc</code>将ts代码编译成js代码。<code>tsc -w</code>监听文件变化自动编译代码。</p>
<p><code>tsc -init</code>可以生成<code>tsconfig.json</code>文件。</p>
使用VSCode调试 javascript/typescript 的一个技巧
https://segmentfault.com/a/1190000017862828
2019-01-11T23:47:12+08:00
2019-01-11T23:47:12+08:00
Midqiu
https://segmentfault.com/u/midqiu
22
<p>vscode中有个调试功能,调试的配置文件<code>launch.json</code>里面有个参数<code>program</code>用来指定调试代码的入口文件,有些项目的入口文件是写死的。而有时候在项目写个代码想单独debug一下还要改参数,debug完之后还要改回去,比较麻烦。那其实这个参数可以指定为<code>${file}</code>,意思是当前文件。那么只需要打开你要debug的文件,然后点击调试按钮就行了,直接运行的是当前的文件。</p>
<p><img src="/img/bVbm65k" alt="clipboard.png" title="clipboard.png"></p>
<p>但如果你和我一样,经常写的是typescript代码(.ts文件),但是调试的时候执行的是.js文件,那只需要这样设置就能自动执行对应的.js代码了。</p>
<pre><code>"program": "${fileDirname}/${fileBasenameNoExtension}.js",</code></pre>
<p><img src="/img/bVbm66f" alt="clipboard.png" title="clipboard.png"></p>
JS/TS 的 import 和 export 用法小结
https://segmentfault.com/a/1190000017419857
2018-12-18T19:17:21+08:00
2018-12-18T19:17:21+08:00
Midqiu
https://segmentfault.com/u/midqiu
56
<p>昨天帮一个网友解决一个typescript的问题,看了一下,归根结底还是对js的import和export用法的不熟悉。让我想起来当年学这个知识点的时候,也是云里雾里跌跌撞撞『猜』了很久用法,踩过坑。<br>当时主要看的是阮一峰的这篇文章 hptt://es6.ruanyifengcom,里面讲了很多怎么实现和许多细节性的东西,当然很全面,只是,对我们作为语言的使用者来说,有点让人抓不到重点,所以按照自己的理解整理了一下。</p>
<p>首先,吐槽一下,单单一个export和import搭配使用的方式就好几种,设计的过于复杂了,记忆和使用的心理负担太重,按我的理解来说,一个功能应该有且只有一种语法糖(忘了这是哪种编程语言的设计哲学了),所以我一段时间内就一直使用一种,我称之为基本使用方式。</p>
<h2>基本用法</h2>
<p>比如模块A 向外部提供变量a1和函数fn供其他模块调用,那么我们在模块B中调用a1和fn。</p>
<pre><code class="javascript">//A.js
var a1=111
function fn(){
}
export {a1,fn} //在文件的底部统一导出,即使有时候导出的变量只有一个也这样写
</code></pre>
<p>那么在B.js中调用的形式就是这样:</p>
<pre><code class="javascript">//B.js
import {a1,fn} from './A'
console.log(a1)
fn()</code></pre>
<p>调用的时候 统一使用 <code>import {xxx,xxx2,xxx3} from 'xxx'</code>的形式调用。<br>当然了如果只用到其中一个变量或函数,那么只需要import进来需要的那个就行了,比如<code>import {a1} from './A'</code>.</p>
<p>但有时候遇到这种情况,名字重复比如B.js里面已经有个变量叫a1了,那么就加个 as 起个别名。</p>
<pre><code class="javascript">//B.js
import {a1 as a111,fn} from './A'
console.log(a111)
fn()</code></pre>
<p>还有一种常用的import是这样的:</p>
<pre><code class="javascript">import * as A from './A'
console.log(A.a1)</code></pre>
<p>这个怎么理解记忆呢,就是A模块在代码里不是这样导出的吗——<code>export {a1,fn} </code> 这里看成导出了一个对象,对应我们<code>import * as A from './A</code>里面的 <code>*</code>,然后我们给它起了个别名叫<code>A</code>,当然叫<code>A</code>是为了记忆使用的方便,你可以叫其他什么<code>abcd</code>,那么调用的时候就是<code>abcd.a1</code> <code>abcd.fn</code>.</p>
<p>以上就是一种 export 和两种import 的搭配使用方式。在我自己早期import和export也是各种组合用,自己把自己搞糊涂了,最后发现就这俩套路翻来覆去的用,就能解决问题。</p>
<h2>各自导出的方式</h2>
<p>当然了,除了自己写代码,还经常调用别人写的代码,比如有这个C模块:</p>
<pre><code class="javascript">export var c1 = 222
//
//
//
export function fn() {
}
</code></pre>
<p>我一般不推荐这种写法,缺点之一是导出的变量或者函数分散在代码的各个地方,没有一个统一管理的地方,另一个缺点是不能够直观的让人理解导出的形式。不过如果是别人写的话我们也没有办法,那我们自己可以在脑子里把他成想象成之前说的的那种导出方式:</p>
<pre><code class="javascript">var c1 = 222
//
//
//
function fn() {
}
export{c1,fn}
</code></pre>
<p>那么怎么import使用就和上面的基本情况一样了,就不赘述了。</p>
<h2>default的用法</h2>
<p>还有一种export用法</p>
<pre><code class="javascript">//C.js
var c1 = 222
//
//
//
function fn() {
}
var c2=222
export { c1,fn}
export default c2</code></pre>
<p>注意这里的c2前面加了个default,那这个有啥用的呢,就是其他模块import的时候能简单点——少写一对大括号。</p>
<pre><code class="javascript">import c2 from "./C";
</code></pre>
<p>当然这里有个所谓的『优点』就是直接起别名<code>import c222 from "./C"</code>相当于<code>import c2 as c222 from "./C"</code> </p>
<p>然后如果我们的代码里还使用了C模块的其他变量或函数,那就要这样了</p>
<pre><code class="javascript">import c2 ,{c1,fn} from "./C";
</code></pre>
<p>你就会发现import的用法瞬间成笛卡尔积复杂起来:加大括号的、不加大括号的、起别名加as的、不加as的、import*的、不带星的再乘以export的分开export的、不分开export的 default和不default的…………</p>
<p>所以还是推荐我文章开始推崇的那种基本写法,虽然死板些,但是能cover到后面的几种情况,本质上后面几种是基本形式的特殊情况,本意设计出来是为了写代码的时候能少写几个字符,可是这东西带来『巨大』的心智成本(理解成本和记忆成本)和时间成本,你别说『哎~那是你水平有限这么简单的东西都搞不定』,但我身边不少bat的程序员都踩过这个坑,假如一个程序员要花十分钟来学习理解记忆,那10个程序员就是100分钟,100个程序员就是1000分钟……100万个程序员就是1000万分钟,按程序员的时薪XX计算,那就是一笔3000万的巨款——有没有被吓到?</p>
<p>并且这东西万恶地增加了代码复杂度……</p>
如何编写一个d.ts文件
https://segmentfault.com/a/1190000009247663
2017-04-30T19:13:42+08:00
2017-04-30T19:13:42+08:00
Midqiu
https://segmentfault.com/u/midqiu
283
<blockquote>这篇文章主要讲怎么写一个typescript的描述文件(以d.ts结尾的文件名,比如xxx.d.ts)。</blockquote><p>总结一下:<br>从类型<code>type</code>角度分为:基本类型(string、number、boolean等)及其混合;复杂类型(class、function、object)及其混合(比如说又是class又是function)。<br>从代码有效范围分为:全局变量、模块变量和又是全局变量又是模块变量的。<br>从定义文件来说:自己写的<code>.d.ts</code>文件和扩展别人写的<code>.d.ts</code>文件。<br>以上三个角度,应该覆盖了描述文件的各个方面了。</p><p>2019.09.12更新说明:</p><pre><code>1.增加了用interface的方式声明函数。
2.增加了在使用模块化导入的情况下如何声明全局变量。
</code></pre><p>2019.05.21更新说明:</p><pre><code>发现了一个关于typescript比较好的入门教程:https://ts.xcatliu.com/basics/declaration-files,这是其中的关于描述文件的文档。
</code></pre><p>2018.12.18更新说明:</p><pre><code>1.增加了全局声明的原理说明。
2.增加了es6的import、export对应的d.ts文件写法。
3.增加了d.ts文件放置位置的说明。
</code></pre><p>最近开始从js转ts了。但是要用到一些描述文件(d.ts),常用的比如jquery等都可以通过 npm下载到别人已经写好的<code>npm install @types/jquery</code>。但是还是有一些小众的或者公司内部的公共库或者以前写过的公用js代码需要自己手动写描述文件。</p><p>之前也从网上面也找了一些资料,但还是看的云里雾里模糊不清,经过一段摸索,将摸索的结果记录下来,也希望可以给别人一个参考。</p><p>如果你只写js,d.ts对你来说也是有用的,大部分编辑器能识别d.ts文件,当你写js代码的时候给你智能提示。效果像这样:</p><p><img src="/img/bVDReN" alt="clipboard.png" title="clipboard.png"></p><p>详情可以看我以前写过的一些文章:<a href="https://segmentfault.com/a/1190000007110845">https://segmentfault.com/a/1190000007110845</a></p><p>通常,我们写js的是时候有两种引入js的方式:<br>1,在html文件中通过<code><script></code>标签全局引入全局变量。<br>2,通过模块加载器require其他js文件:比如这样<code>var j=require('jquery')</code>。</p><h2>全局类型</h2><p>首先以第一种方式举例。</p><h3>变量</h3><p>比如现在有一个全局变量,那对应的d.ts文件里面这样写。</p><pre><code class="typesscript">declare var aaa:number</code></pre><p>其中关键字<code>declare</code>表示声明的意思。<strong>在d.ts文件里面,在最外层声明变量或者函数或者类要在前面加上这个关键字。在typescript的规则里面,如果一个<code>.ts</code>、<code>.d.ts</code>文件如果没有用到import或者export语法的话,那么最顶层声明的变量就是全局变量。</strong></p><p>所以我们在这里声明了一个全局变量aaa,类型是数字类型(number)。当然了也可以是string类型或者其他或者:</p><pre><code class="typesscript">declare var aaa:number|string //注意这里用的是一个竖线表示"或"的意思</code></pre><p>如果是常量的话用关键字const表示:</p><pre><code class="typesscript">declare const max:200</code></pre><h3>函数</h3><p>由上面的全局变量的写法我们很自然的推断出一个全局函数的写法如下:</p><pre><code class="typescript">/** id是用户的id,可以是number或者string */
decalre function getName(id:number|string):string</code></pre><p>最后的那个string表示的是函数的返回值的类型。如果函数没有返回值可以用void表示。<br>在js里面调用的时候就会提示:<br><img src="/img/bVLuCP" alt="clipboard.png" title="clipboard.png"><br>我们上面写的注释,写js的时候还可以提示。</p><p>有时候同一个函数有若干种写法:</p><p><img src="/img/bVMXTD" alt="clipboard.png" title="clipboard.png"></p><pre><code class="typescript">get(1234)
get("zhangsan",18)</code></pre><p>那么d.ts对应的写法:</p><pre><code class="typesscript">declare function get(id: string | number): string
declare function get(name:string,age:number): string</code></pre><p>如果有些参数可有可无,可以加个<code>?</code>表示非必须。</p><pre><code class="typesscript">declare function render(callback?:()=>void): string</code></pre><p>js中调用的时候,回调传不传都可以:</p><pre><code class="javascript">render()
render(function () {
alert('finish.')
})</code></pre><h3>用interface 声明函数</h3><p>也可以用interface去声明函数类型:</p><p><img src="/img/bVbxExG" alt="clipboard.png" title="clipboard.png"></p><pre><code class="typescript">
//Get是一种类型
declare interface Get{
(id: string): string
(name:string,age:number):string
}
//get是Get类型的
declare var get:Get</code></pre><p>用起来长这个样子:<br><img src="/img/bVbxExy" alt="clipboard.png" title="clipboard.png"></p><h3>class</h3><p>当然除了变量和函数外,我们还有类(class)。</p><pre><code class="typesscript">declare class Person {
static maxAge: number //静态变量
static getMaxAge(): number //静态方法
constructor(name: string, age: number) //构造函数
getName(id: number): string
}</code></pre><p><code>constructor</code>表示的是构造方法:</p><p><img src="/img/bVMXy0" alt="clipboard.png" title="clipboard.png"></p><p><img src="/img/bVMXzk" alt="clipboard.png" title="clipboard.png"></p><p>其中static表示静态的意思,用来表示静态变量和静态方法:</p><p><img src="/img/bVMXAV" alt="clipboard.png" title="clipboard.png"></p><p><img src="/img/bVMXAg" alt="clipboard.png" title="clipboard.png"></p><h3>对象</h3><pre><code class="typescript">declare namespace OOO{
}</code></pre><p>当然了这个对象上面可能有变量,可能有函数可能有类。</p><pre><code class="typescript">declare namespace OOO{
var aaa: number | string
function getName(id: number | string): string
class Person {
static maxAge: number //静态变量
static getMaxAge(): number //静态方法
constructor(name: string, age: number) //构造函数
getName(id: number): string //实例方法
}
}</code></pre><p>其实就是把上面的那些写法放到这个namespace包起来的大括号里面,注意括号里面就不需要declare关键字了。<br>效果:</p><p><img src="/img/bVMXBu" alt="clipboard.png" title="clipboard.png"></p><p><img src="/img/bVMXBv" alt="clipboard.png" title="clipboard.png"></p><p><img src="/img/bVMXBB" alt="clipboard.png" title="clipboard.png"></p><p>对象里面套对象也是可以的:</p><pre><code class="typescript">declare namespace OOO{
var aaa: number | string
// ...
namespace O2{
let b:number
}
}</code></pre><p>效果:</p><p><img src="/img/bVMXB5" alt="clipboard.png" title="clipboard.png"></p><h3>混合类型</h3><p>有时候有些值既是函数又是class又是对象的复杂对象。比如我们常用的jquery有各种用法:</p><pre><code class="javascript">new $()
$.ajax()
$()</code></pre><h4>既是函数又是对象</h4><pre><code class="typescript">declare function $2(s:string): void
declare namespace $2{
let aaa:number
}</code></pre><p>效果:</p><p>作为函数用:<br><img src="/img/bVMXJ8" alt="clipboard.png" title="clipboard.png"></p><p>作为对象用:<br><img src="/img/bVMXKa" alt="clipboard.png" title="clipboard.png"></p><p>也就是ts会自动把同名的namespace和function合并到一起。</p><h4>既是函数,又是类(可以new出来),又是对象</h4><pre><code class="typescript">// 实例方法
interface People{
name: string
age: number
getName(): string
getAge():number
}
interface People_Static{
/** 构造函数 */
new (name: string, age: number): People
new (id:number): People
/** 作为对象,调用对象上的方法或者变量 */
staticA():number
aaa:string
/** 作为函数使用 */
(w:number):number
(w:string):number
}
declare var People:People_Static</code></pre><p>ts3.6增加了新功能,function声明和class声明可以合并了,所以又有了新的写法:</p><pre><code class="typescript">/** 作为函数使用 */
declare function People(w: number): number
declare function People(w: string): number
declare class People {
/** 构造函数 */
constructor(name: string, age: number)
constructor(id: number)
// 实例属性和实例方法
name: string
age: number
getName(): string
getAge(): number
/** 作为对象,调用对象上的方法或者变量 */
static staticA(): number
static aaa: string
}
/** 作为对象,调用对象上的方法或者变量 */
declare namespace People {
export var abc: number
}</code></pre><p>函数用<code>function</code>,类用<code>class</code>声明,复杂对象就用<code>namespace</code>,这样的对应关系简洁明了。</p><p>效果:</p><p>作为函数使用:<br><img src="/img/bVMXNA" alt="clipboard.png" title="clipboard.png"></p><p>类的静态方法:<br><img src="/img/bVMXNN" alt="clipboard.png" title="clipboard.png"></p><p>类的构造函数:<br><img src="/img/bVMXNB" alt="clipboard.png" title="clipboard.png"><br>类的实例方法:<br><img src="/img/bVMXNE" alt="clipboard.png" title="clipboard.png"></p><h2>模块化的全局变量</h2><p>这个是怎么回事呢,就是有时候我们定义全局变量的时候需要引入(别人写的)文件,比如这样的,我想声明个全局变量req:</p><p><img src="/img/bVbxEAj" alt="clipboard.png" title="clipboard.png"></p><p>由于我们当前的d.ts文件使用了import/export语法,那么ts编译器就不把我们通过<code>declare var xxx:yyy</code>当成了全局变量了,那么我们就需要通过以下的方式声明全局变量:</p><pre><code class="typescript">
import { Request,Response} from 'express'
declare global {
var req: Request
var res: Response
namespace OOO {
var a:number
}
}</code></pre><p>用起来长这个样子:</p><p><img src="/img/bVbxEBp" alt="clipboard.png" title="clipboard.png"><br>其他类型(number、string blabla)就不一一举例了,参照上面的例子去掉declare填到global的大括号下就行了。</p><h2>模块化(CommonJS)</h2><p>除了上面的全局的方式,我们有时候还是通过require的方式引入模块化的代码。</p><p>比如这样的效果:</p><p><img src="/img/bVMXOl" alt="clipboard.png" title="clipboard.png"></p><p>对应的写法是这样的:</p><pre><code class="typescript">declare module "abcde" {
export let a: number
export function b(): number
export namespace c{
let cd: string
}
}</code></pre><p>其实就是外面套了一层 <code>module "xxx"</code>,里面的写法和之前其实差不多,把<code>declare</code>换成了<code>export</code>。</p><p>此外,有时候我们导出去的是一个函数本身,比如这样的:</p><p><img src="/img/bVMXOU" alt="clipboard.png" title="clipboard.png"></p><p>对应的写法很简单,长这个样子:</p><pre><code class="typescript">declare module "app" {
function aaa(some:number):number
export=aaa
}</code></pre><p>以此类推,导出一个变量或常量的话这么写:</p><pre><code class="typescript">declare module "ccc" {
const c:400
export=c
}</code></pre><p>效果:</p><p><img src="/img/bVMXPc" alt="clipboard.png" title="clipboard.png"></p><h2>ES6的模块化方式(import export)</h2><pre><code class="typescript">declare var aaa: 1
declare var bbb: 2
declare var ccc: 3 //因为这个文件里我们使用了import或者export语法,所以bbb和ccc在其他代码里不能访问到,即不是全局变量
export { aaa }</code></pre><p>使用:</p><pre><code class="typescript">import { a1, a2 } from "./A"
console.log(a1)
console.log(a2)
</code></pre><p>那么对应的A.d.ts文件是这样写的:</p><pre><code class="typescript">declare var a1: 1
declare var a2: 2
export { a1,a2 }</code></pre><p>当然了也能这样写:</p><pre><code class="typescript">export declare var a1: 1
export declare var a2: 2
</code></pre><p>不过建议之前的第一种写法,原因看这里<a href="https://segmentfault.com/a/1190000017419857">https://segmentfault.com/a/1190000017419857</a></p><p>当然了还有人经常问default导出的写法:</p><pre><code class="typescript">declare var a1: 1
export default a1</code></pre><p>使用的时候当然就是这样用了:</p><pre><code class="typescript">import a1 from "./A";
console.log(a1)</code></pre><h2>UMD</h2><p>有一种代码,既可以通过全局变量访问到,也可以通过require的方式访问到。比如我们最常见的jquery:</p><p><img src="/img/bVMXPg" alt="clipboard.png" title="clipboard.png"><br><img src="/img/bVMXPf" alt="clipboard.png" title="clipboard.png"></p><p>其实就是按照全局的方式写d.ts,写完后在最后加上<code>declare module "xxx"</code>的描述:</p><pre><code class="typescript">declare namespace UUU{
let a:number
}
declare module "UUU" {
export =UUU
}</code></pre><p>效果这样:</p><p>作为全局变量使用:<br><img src="/img/bVMXPB" alt="clipboard.png" title="clipboard.png"></p><p>作为模块加载使用:<br><img src="/img/bVMXPM" alt="clipboard.png" title="clipboard.png"></p><h2>其他</h2><p>有时候我们扩展了一些内置对象。比如我们给Date增加了一个format的实例方法:</p><p><img src="/img/bVMXRR" alt="clipboard.png" title="clipboard.png"></p><p>对应的d.ts描述文件这样写:</p><pre><code class="typescirpt">interface Date {
format(f: string): string
}</code></pre><h2>.d.ts文件放到哪里</h2><p>经常有人问写出来的d.ts文件(A.d.ts)文件放到哪个目录里,如果是模块化的话那就放到和源码(A.js)文件同一个目录下,如果是全局变量的话理论上放到哪里都可以————当然除非你在tsconfig.json 文件里面特殊配置过。</p>
使用 webstorm 写 typescript 的一些小技巧
https://segmentfault.com/a/1190000007199696
2016-10-18T10:57:00+08:00
2016-10-18T10:57:00+08:00
Midqiu
https://segmentfault.com/u/midqiu
0
<p>记录使用过程中的一些问题和解决办法,会不断完善。</p>
<h2>导入项目的全局库</h2>
<p>新版的webstorm中会自动解析<code>node_modules/@types</code>目录下的ts文件。那当有些文件不在此目录下的话就需要手动指定目录了。<br>将指定文件夹作为代码的libary库加进来:</p>
<p><img src="/img/bVEm6M?w=1427&h=508" alt="clipboard.png" title="clipboard.png"></p>
<p>这时候再编译就不报错了:</p>
<p><img src="/img/bVEm64?w=403&h=87" alt="clipboard.png" title="clipboard.png"></p>
使用typescript写node的一些小技巧
https://segmentfault.com/a/1190000007183406
2016-10-16T16:32:46+08:00
2016-10-16T16:32:46+08:00
Midqiu
https://segmentfault.com/u/midqiu
1
<h2>当代码出错的时候提示对应的ts文件</h2>
<p><img src="/img/bVEiS3?w=685&h=265" alt="clipboard.png" title="clipboard.png"></p>
<p>1,安装</p>
<pre><code>npm install source-map-support --save</code></pre>
<p>2,在入口文件:</p>
<pre><code>import 'source-map-support/register';</code></pre>
<p><img src="/img/bVEiS9?w=684&h=173" alt="clipboard.png" title="clipboard.png"></p>
<h2>VSCode编辑器中隐藏编译后的文件:</h2>
<p><img src="/img/bVEiTi?w=187&h=239" alt="clipboard.png" title="clipboard.png"></p>
<p><code>setting.json</code>配置文件中如下修改:</p>
<pre><code> "files.exclude": {
"**/*.js": true,
"**/*.js.map": true
},</code></pre>
<p><img src="/img/bVEiTn?w=173&h=98" alt="clipboard.png" title="clipboard.png"></p>
<h2>指定编译后的js的输入目录</h2>
<p>如果你不想想上面那样把js编译在和ts源码同级目录中可以在<code>tsconfig.json</code>增加如下配置指定编译目录。</p>
<p><img src="/img/bVML4E?w=224&h=53" alt="clipboard.png" title="clipboard.png"></p>
<p>当调试的需要在VSCode的调试配置文件<code>launch.json</code>中增加如下配置:<br><img src="/img/bVML4B?w=427&h=104" alt="clipboard.png" title="clipboard.png"></p>