TS 笔记一 HelloWorld和环境搭建

一、安装TS,完成HelloWorld

参考TypeScript 安装

1.nodejs/npm安装

首先要安装npm,参考js nodejs npm之间的关系+npm安装备忘

为了版本切换方便,建议安装nvm,参考使用nvm解决gulp ReferenceError: primordials is not defined

2.使用npm安装TS
//使用国内镜像
npm config set registry https://registry.npmmirror.com
npm install -g typescript

安装完成后我们可以使用 tsc 命令来执行 TypeScript 的相关代码,以下是查看版本号:

E:\ts\HelloWorld>tsc -v
Version 4.5.5
3.新建greeter.ts
let v = "hello world";
console.log(v);
4.打开命令行使用tsc生成js并运行
image.png
tsc greeter.ts//生成greeter.js
node greeter.js//运行
二、配置VS Code
1.安装VS Code

下载地址:https://code.visualstudio.com/。
如果下载速度过慢,参考https://www.cnblogs.com/onceweb/articles/15536291.html,原本的下载链接:https://az764295.vo.msecnd.net/stable/f80445acd5a3dadef24aa209168452a3d97cc326/VSCodeSetup-x64-1.64.2.exe,将前面的CDN节点替换掉:http://vscode.cdn.azure.cn/stable/f80445acd5a3dadef24aa209168452a3d97cc326/VSCodeSetup-x64-1.64.2.exe,就可以按正常速度下载了.

2.运行报错
image.png
[Running] ts-node "e:\ts\HelloWorld\greeter.ts"
'ts-node' �����ڲ����ⲿ���Ҳ���ǿ����еij���
���������ļ���

报错信息中,出现了ts-node,那这个东西可以百度一下看看干啥的。

当我们用 Typesript 来写 Node.js 的代码,写完代码之后要用 tsc 作编译,之后再用 Node.js 来跑,这样比较麻烦,所以我们会用 ts-node 来直接跑 ts 代码,省去了编译阶段。

3.安装ts-node,注意这一步失败了,解决方案在后面

参考
使用ts-node直接运行ts脚本
如何在VS Code中使用ts-node调试TypeScript
手写一个 ts-node 来深入理解它的原理

这个参考上面的链接,是说不能全局安装,会报错。其实为了各项目的版本管理方便,建议还是本地安装。

注意,在安装之前,最好先使用npm init命令将package.json生成,否则会提示:npm WARN saveError ENOENT: no such file or directory, open 'E:\ts\learnTsconfig\package.json'

然后执行如下命令:

npm i ts-node -D

现在,执行ts-node greeter.ts

ts-node : 无法将“ts-node”项识别为 cmdlet、函数、脚本文件或
可运行程序的名称。请检查名称的拼写,如果包括路径
,请确保路径正确,然后再试一次。
所在位置 行:1 字符: 1
+ ts-node greeter.ts
+ ~~~~~~~
    + CategoryInfo          : ObjectNotFound: (ts-node:String) [], 
CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

这是怎么回事,去官网看一下:https://github.com/TypeStrong/ts-node,没有找到针对性的解决方案,改成全局安装ts-node还是报错:

E:\ts\HelloWorld>ts-node
d:\nvm\v8.11.2\node_modules\ts-node\dist\repl.js:178
                    catch { }
                          ^

SyntaxError: Unexpected token {
    at createScript (vm.js:80:10)

又参考以下链接,还是没解决掉。
搭建一套支持TS的Node运行环境
ts-node 的那些坑

4.安装特定版本的ts-node

然后怀疑是npm的版本或者ts-node的版本兼容问题,后来参考使用ts-node demo.ts命令报错,使用了ts-node的老版本,解决掉了。

使用 npm uni -g ts-node 卸载掉ts-node
再使用 npm i -g [email protected]下载旧一点的版本

5.断点调试

参考VSCode使用ts-node 调试TypeScript代码

为了断点调试,我们需要在tsconfig.json中开启sourceMap,然后为ts-node注册一个vsc的debug任务,修改项目的launch.json文件

{
    "name": "Current TS File",
    "type": "node",
    "request": "launch",
    "args": [
        "${workspaceRoot}/greeter.ts" // 入口文件
    ],
    "runtimeArgs": [
        "--nolazy",
        "-r",
        "ts-node/register"
    ],
    "sourceMaps": true,
    "cwd": "${workspaceRoot}",
    "protocol": "inspector",
    "console": "integratedTerminal",
    "internalConsoleOptions": "neverOpen"
}

image.png

按F5就弹出了这个,可是把launch.json中的注释去掉,还是报错。
参考以下这个,并未解决:
https://stackoverflow.com/questions/70441188/debug-a-json-with-comments

参考如何在VS Code中使用ts-node调试TypeScript
launch.json :

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Current TS File",
            "type": "node",
            "request": "launch",
            "program": "${workspaceRoot}/node_modules/ts-node/dist/bin.js",
            "args": [
                "${relativeFile}"
            ],
            "cwd": "${workspaceRoot}",
            "protocol": "inspector"
        }
    ]
}

因为我们是全局安装的ts-node,所以要把program路径改成实际的安装位置。但是运行起来,发现没报错,但也没输出

d:\nodejs\node.exe d:\nodejs\node_modules\ts-node\dist\bin.js greeter.ts

那没办法,把ts-node安装到本地项目中,再试一下,发现报错了:

Error: Cannot find module 'typescript'

没办法,把typescript也安装到本地,重新 运行,发现没报错,也没输出……

参考https://gist.github.com/cecilemuller/2963155d0f249c1544289b78a1cdd695还是不行

最后,换了一台电脑,解决了,原因还不清楚,估计和版本有关……

6.终端无法运行npm命令

参考【VSCODE】解决VSCODE“因为在此系统上禁止运行脚本“报错

  • 以管理员身份运行vscode
  • 终端运行 get-ExecutionPolicy ==>Restricted,表示状态是禁止的
  • 终端运行 set-Execu tionPolicy RemoteSigned
7.参考vscode生成快捷注释模板的方法

按下shift+ctrl+p,输入snippets,新建全局代码文件片段,自定义文件名称,然后回车,就进入到了文件:

{
    "My comments": {
        "scope": "javascript,typescript",
        "prefix": "//.",
        "body": [
            "/**",
            "* @description: ",
            "* @author:      ",
            "* @date:        $CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND",
            "* @version:     V1.0.0",
            "*/"
        ],
        "description": "my comments"
    }
}

在代码中输入//,回车即可

8.条件断点

如图,在断点窗口点那个小铅笔,输入表达式即可:


image.png
image.png
三、@types 类型定义

参考
在 Typescript 2.0 中使用 @types 类型定义
types 和 @types 是什么?

基于 Typescript 开发的时候,很麻烦的一个问题就是类型定义。导致在编译的时候,经常会看到一连串的找不到类型的提示。解决的方式经过了许多的变化,从 DefinitelyTyped 到 typings。最后是 @types。在 Typescript 2.0 之后,推荐使用 @types 方式。

1.TSD(已过时,不推荐)

参考
知乎 现在 TypeScript 的生态如何

npm install tsd -g
tsd install jquery --save
2.typings(已过时,不推荐)
npm install typings --global
typings install react --save
3.@types 类型定义

在 Typescript 2.0 之后,TypeScript 将会默认的查看 ./node_modules/@types 文件夹,自动从这里来获取模块的类型定义,当然了,你需要独立安装这个类型定义。

比如,你希望 core.js 的类型定义,那么,你需要安装这个库的定义库。

npm install --save @types/core-js

与我们安装一个普通的库没有区别。当然了,常用的 jquery 也有。Microsoft 在 The Future of Declaration Files 介绍了 TypeScript 的这个新特性。

4.一个例子

这里我通过一个例子来说明一下什么是 @types,这样大家理解起来更深刻一点。

当我们用 npm 等包管理工具安装第三方包的时候,有些包并不是 TypeScript 编写的,自然也不会导出 TypeScript 声明文件。这种情况下,如果我们在 TypeScript 项目中引入了这种包,则会编译报错(没有设置 allowJS)。举个例子,当我们通过npm install jquery --save 安装 jquery 包并引用的时候,TypeScript 会报错。

allowJS 是 TypeScript 1.8 引进的一个编译项。

报错内容如下:

Could not find a declaration file for module ‘jquery’. Try npm install @types/jquery if it exists or add a new declaration (.d.ts) file containing declare module 'jquery';

这里的意思是 TypeScript 没有找到 jquery 这个包的定义,你可以通过npm install @types/jquery安装相关声明,或者自己定义一份.d.ts 文件,并将 jquery 声明为 module。

全世界不是 TypeScript 编写的包多了去了。即使你的包是 TypeScript 编写的,如果你没有导出声明文件,也是没用的。(TypeScript 默认不会导出声明文件,只会编译输出 JavaScript 文件)。因此 TypeScript 必须对这种情况提供解决方案,而上面的两种方案(安装 @types 和 自己 declare module)就是 TypeScript 官方提出的, 你可以选择适合你的方案。我的推荐是尽量使用 @types 下的声明,实在没有,再使用第二种方法。

值得一提的是,并不是所有的包都可以通过这种方式解决的, 能解决的是 DefinitelyTyped 组织已经写好定义的包, 好消息是比较流行的包基本都有。 如果你想查一个包是否在 @type 下,可以访问 https://microsoft.github.io/TypeSearch/

那么 TypeScript 是怎么找定义的,什么情况会找不到定义而报类似上面举的例子的错误,这里简单介绍下原理。

5.包类型定义的查找

就好像 node 的包查找是先在当前文件夹找 node_modules,在它下找递归找,如果找不到则往上层目录继续找,直到顶部一样, TypeScript 类型查找也是类似的方式。

具体来说就是:

  • TypeScript 编译器先在当前编译上下文找 jquery 的定义。
  • 如果找不到,则会去 node_modules 中的@types (默认情况,目录可以修改,后面会提到)目录下去寻找对应包名的模块声明文件。

@types/*模块声明文件由社区维护,通过发布到@types 空间下。 GitHub - DefinitelyTyped/DefinitelyTyped: The repository for high quality TypeScript type definitions.

6.变量类型定义的查找

和包查找类似,默认情况下变量类型定义的查找也会去 @types 下去寻找。只不过并不是直接去 @types 找,而是有一定的优先级, 这个过程类似原型链或者作用域链。

比如如下代码:

const user: User = { name: "lucifer" };

Typescript 则会先在本模块查找 User 的定义。如果找到,则直接返回。 如果找不到, 则会到全局作用域找,而这个全局默认就是指的就是 @types 下的所有类型定义。(注意目录页是可以配的)

也就是说 @types 下的定义都是全局的。当然你可以导入 @types 下导出的定义,使得它们的作用域变成你的模块内部。

7.typeRoots 与 types

前面说了 TypeScript 会默认引入node_modules下的所有@types声明,但是开发者也可以通过修改tsconfig.json的配置来修改默认的行为.

tsconfig.json 中有两个配置和类型引入有关。

typeRoots: 用来指定默认的类型声明文件查找路径,默认为node_modules/@types, 指定typeRoots后,TypeScript 编译器会从指定的路径去引入声明文件,而不是node_modules/@types, 比如以下配置会从typings路径下去搜索声明

{
  "compilerOptions": {
    "typeRoots": ["./typings"]
  }
}

types: TypeScript 编译器会默认引入typeRoot下所有的声明文件,但是有时候我们并不希望全局引入所有定义,而是仅引入部分模块。这种情景下可以通过types指定模块名只引入我们想要的模块,比如以下只会引入 jquery 的声明文件

{
  "compilerOptions": {
    "types": ["jquery"]
  }
}

比如:

{
   "compilerOptions": {
       "types" : ["node", "lodash", "express"]
   }
}

这样将只会包含 ./node_modules/@types/node, ./node_modules/@types/lodash 和 ./node_modules/@types/express ,其它的则不会被包含进来。

如果配置为"types": []则不会包含任何包。

8.总结
  • typeRoots 是 tsconfig 中 compilerOptions 的一个配置项,typeRoots 下面的包会被 ts 编译器自动包含进来,typeRoots 默认指向 node_modules/@types。
  • @types 是 scoped packages(感谢 Mickey 的指出 ),和@babel 类似。@types 下的所有包会默认被引入,你可以通过修改 compilerOptions 来修改默认策略。
  • types 和 typeRoots 一样也是 compilerOptions 的配置,指定 types 后,typeRoots 下只有被指定的包才会被引入。
9.实践

首先,使用npm init生成默认的package.json,参考npm package.json scripts

然后npm i -D @types/node,在本地安装NodeJs的类型声明

四、自定义的d.ts

参考
TypeScript 中的 .d.ts 文件有什么作用
如何编写一个d.ts文件
TypeScript Handbook(中文版)

说白了就是定义了一些接口,使得你用typescript编程的时候调用此模块,IDE有提示。。。当然还会定义很多export的数据类型,和inferface 供外部模块调用。很显然就是数据规范。e.gtypescript:import * as mysql from 'mysql';翻译成js 就是:require('mysql')其实就是做了一层符合typescript的数据规范。

1.全局变量
declare var aaa:number
declare var aaa:number|string //注意这里用的是一个竖线表示"或"的意思
declare const max:200 //常量
2.全局函数
/** id是用户的id,可以是number或者string */
decalre function getName(id:number|string):string

有时候同一个函数有若干种写法:

get(1234)
get("zhangsan",18)

那么d.ts对应的写法:

declare function get(id: string | number): string
declare function get(name:string,age:number): string
3.类
declare class Person {
    static maxAge: number //静态变量
    static getMaxAge(): number //静态方法
    constructor(name: string, age: number)  //构造函数
    getName(id: number): string 
}
4.带属性的对象

全局变量myLib包含一个makeGreeting函数, 还有一个属性numberOfGreetings指示目前为止欢迎数量。

let result = myLib.makeGreeting("hello, world");
console.log("The computed greeting is:" + result);
let count = myLib.numberOfGreetings;

使用declare namespace描述用点表示法访问的类型或值。

declare namespace myLib {
    function makeGreeting(s: string): string;
    let numberOfGreetings: number;
}
5.prototype

prototype类型需要与class保持一致

你可能感兴趣的:(TS 笔记一 HelloWorld和环境搭建)