typescript入门

174 阅读7分钟

安装TypeScript

有两种主要的方式来获取TypeScript工具:

  • 通过npm(Node.js包管理器)
  • 安装Visual Studio的TypeScript插件

TypeScript 的安装很简单,你可以通过npm直接在全局安装 TypeScript。

 npm install -g typescript

npm的服务器在国外,访问比较慢,可以更换成国内源:

npm config set registry https://registry.npm.taobao.org

当然也可以安装cnpm(采用的国内源),使用时需要npm命令的地方都换成cnpm

npm install -g cnpm --registry=https://registry.npm.taobao.org

企业微信截图_16039423457921.png

创建环境

我们创建一个目录并且进入该目录

mkdir ts-study && cd ts-study

接着创建src目录

mkdir src

在src下面创建index.ts,也可以手动创建

touch src/index.ts

以上两个的合并命令是

mkdir src && touch src/index.ts

接下来目录初始化

npm init

企业微信截图_16039431179898.png
我们要使用TypeScript 的话通常也需要初始化:

tsc --init

这个时候你会发现目录下多了一个tsconfig.json文件.
这是 TypeScript 的配置文件,里面已经包含官方初始化的一些配置以及注释,我们现在进行自定义的配置:

{
  "compilerOptions": {
    "target": "es5",                            // 指定 ECMAScript 目标版本: 'ES5'
    "module": "commonjs",                       // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
    "moduleResolution": "node",                 // 选择模块解析策略
    "experimentalDecorators": true,             // 启用实验性的ES装饰器
    "allowSyntheticDefaultImports": true,       // 允许从没有设置默认导出的模块中默认导入。
    "sourceMap": true,                          // 把 ts 文件编译成 js 文件的时候,同时生成对应的 map 文件
    "strict": true,                             // 启用所有严格类型检查选项
    "noImplicitAny": true,                      // 在表达式和声明上有隐含的 any类型时报错
    "alwaysStrict": true,                       // 以严格模式检查模块,并在每个文件里加入 'use strict'
    "declaration": true,                        // 生成相应的.d.ts文件
    "removeComments": true,                     // 删除编译后的所有的注释
    "noImplicitReturns": true,                  // 不是函数的所有返回路径都有返回值时报错
    "importHelpers": true,                      // 从 tslib 导入辅助工具函数
    "lib": ["es6", "dom"],                      // 指定要包含在编译中的库文件
    "typeRoots": ["node_modules/@types"],
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": [                                  // 需要编译的ts文件一个*表示文件匹配**表示忽略文件的深度问题
    "./src/**/*.ts"
  ],
  "exclude": [                                  //部需要编译的文件
    "node_modules",
    "dist",
    "**/*.test.ts",
  ]
}

完整的tsconfig.json文件好像是这样的:

{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig.json to read more about this file */

    /* Basic Options */
    // "incremental": true,                   /* 启动增量编译 */
    "target": "es5",                          /* 指定 ECMAScript 目标版本: 'ES3' (默认), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "commonjs",                     /* 指定使用模块: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
    "lib": ["es6", "dom"],                             /* 指定要包含在编译中的库文件 */
    // "allowJs": true,                       /* 允许编译 javascript 文件。 */
    // "checkJs": true,                       /* 检查js的错误 */
    // "jsx": "preserve",                     /* 指定 JSX 代码生成: 'preserve', 'react-native', or 'react'. */
    "declaration": true,                   /* 生成相应的.d.ts文件 */
    // "declarationMap": true,                /* 为每个源图生生成相应的.d.ts文件 */
    "sourceMap": true,                     /* 把 ts 文件编译成 js 文件的时候,同时生成对应的 map 文件*/
    // "outFile": "./",                       /* 串联并输出到单个文件。 */
    "outDir": "./dist",                      /* 将输出结构重定向到目录。 */
    "rootDir": "./src",                       /* 指定输入文件的根目录。用于使用 -outDir 控制输出目录结构。 */
    // "composite": true,                     /* 启用项目编译 */
    // "tsBuildInfoFile": "./",               /* 指定文件以增量存储编译信息 */
    "removeComments": true,                /*  删除编译后的所有的注释 */
    // "noEmit": true,                        /* Do not emit outputs. */
    "importHelpers": true,                 /* 从 tslib 导入辅助工具函数 */
    // "downlevelIteration": true,            /* 在定位"ES5"或"ES3"时,对"for-of"、传播和销毁中的可操作数据提供完全支持。*/
    // "isolatedModules": true,               /* 将每个文件作为单独的模块转堆(类似于 'ts)。转位模块')。 */

    /* Strict Type-Checking Options */
    "strict": true,                           /* 启用所有严格类型检查选项 */
    "noImplicitAny": true,                 /* 在表达式和声明上有隐含的 any类型时报错 */
    // "strictNullChecks": true,              /* 启用严格的空检查。 */
    // "strictFunctionTypes": true,           /* 启用对函数类型的严格检查。 */
    // "strictBindCallApply": true,           /* 在函数上启用严格的"bind"、"call"和"apply"方法。 */
    // "strictPropertyInitialization": true,  /* 启用对类中属性初始化的严格检查。 */
    // "noImplicitThis": true,                /* 在"this"表达式上引发与隐含的"任何"类型的错误。 */
    "alwaysStrict": true,                  /* 以严格模式检查模块,并在每个文件里加入 'use strict' */

    /* Additional Checks */
    // "noUnusedLocals": true,                /* 报告未使用局部变量的错误。 */
    // "noUnusedParameters": true,            /* 报告未使用参数的错误。 */
    "noImplicitReturns": true,             /* 不是函数的所有返回路径都有返回值时报错 */
    // "noFallthroughCasesInSwitch": true,    /* 报告开关语句中掉线情况的错误。*/

    /* Module Resolution Options */
    "moduleResolution": "node",            /* 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                       /* 用于解析非绝对模块名称的基目录。 */
    // "paths": {},                           /* 将导入重新映射到相对于"baseUrl"的位置的一系列条目。 */
    // "rootDirs": [],                        /*  */
    "typeRoots": ["node_modules/@types"],                       /* 其组合内容在运行时表示项目结构的根文件夹列表。 */
    // "types": [],                           /* 键入要包含在编译中的声明文件。*/
    "allowSyntheticDefaultImports": true,  /* 允许从没有设置默认导出的模块中默认导入 */
    "esModuleInterop": true,                  /* 通过创建所有导入的命名空间对象,实现 CommonJS 和 ES 模块之间的发出互操作性。暗示 "允许合成默认"。 */
    // "preserveSymlinks": true,              /* 不要解析符号链接的真实路径。 */
    // "allowUmdGlobalAccess": true,          /* 允许从模块全局访问 UMD 。 */

    /* Source Map Options */
    // "sourceRoot": "",                      /* 指定调试器应查找 TypeScript 文件的位置,而不是源位置。 */
    // "mapRoot": "",                         /* 指定调试器应查找地图文件的位置,而不是生成的位置。*/
    // "inlineSourceMap": true,               /* 使用源映射发出单个文件,而不是具有单独的文件。 */
    // "inlineSources": true,                 /* 在单个文件中将源与源映射一起发出;需要设置 "- - 内联源地图" 或 "- - 源映射" 。 */

    /* Experimental Options */
    "experimentalDecorators": true,        /* 启用实验性的ES装饰器 */
    // "emitDecoratorMetadata": true,         /* 支持为修饰器发出类型元数据的实验支持。*/

    /* Advanced Options */
    "skipLibCheck": true,                     /* 跳过声明文件的类型检查。*/
    "forceConsistentCasingInFileNames": true  /* 不允许对同一文件的不一致引用。 */
  },
  "include": [                                  // 需要编译的ts文件一个*表示文件匹配**表示忽略文件的深度问题
    "./src/**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "dist",
    "**/*.test.ts",
  ]
}

然后在package.json中加入我们的script命令:

{
  "name": "ts-study",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.ts",
  "scripts": {
    "build": "tsc", // 编译
    "build:w": "tsc -w" // 监听文件,有变动即编译
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "typescript ": "^3.6.4"
  }
}

编写第一个 TypeScript 程序

src/index.ts中输入以下代码:

function greeter(person) {
    return "Hello, " + person
}

const user = "Jane User";

这个时候你会看到一个警告,这个警告在官方默认配置中是不会出现的,正是由于我们开启了 noImplicitAny 选项,对于隐式含有 any 类型的参数或者变量进行警告⚠️.


之所以一开始就开启严格模式,是因为一旦你开始放任any类型的泛滥,就会把 TypeScript 变成 AnyScript ,会很难改掉这个恶习,所以从一开始就要用规范的 TypeScript 编码习惯。
我们进行修改如下:

function greeter(person: string) {
    return "Hello, " + person;
}

此时我们可以看到,greeter函数自动加上了返回值类型,这是 TypeScript 自带的_类型推导_。

接下来我们编译这个index.ts

tsc src/index.ts

输出一个index.js的文件它包含了和输入文件中相同的JavsScript代码。
如图
企业微信截图_16039561718956.png
接下来我们写一个完整的示例,并运行它
index.ts

/* 创建一个 Student类 */
class Student {
    fullName: string;
    constructor(public firstName: string, public middleInitial: string, public lastName: string) {
        this.fullName = firstName + " " + middleInitial + " " + lastName;
    }
}
/* 创建一个 Person 接口 */
interface Person {
    firstName: string;
    lastName: string;
}

function greeter(person : Person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

let user = new Student("Jane", "M.", "User");

document.body.innerHTML = greeter(user);

然后我们能编译这个ts

tsc src/index.ts

编译后生成的index.js文件如下:

/* 创建一个 Student类 */
var Student = /** @class */ (function () {
    function Student(firstName, middleInitial, lastName) {
        this.firstName = firstName;
        this.middleInitial = middleInitial;
        this.lastName = lastName;
        this.fullName = firstName + " " + middleInitial + " " + lastName;
    }
    return Student;
}());
function greeter(person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}
var user = new Student("Jane", "M.", "User");
document.body.innerHTML = greeter(user);

然后我们新建一个index.html文件,代码如下:

<!DOCTYPE html>
<html>
    <head><title>TypeScript Greeter</title></head>
    <body>
        <script src="index.js"></script>
    </body>
</html>

最后我们在浏览器中打开index.html,浏览器显示如下
企业微信截图_16039594751625.png
到此我们就完整的运行了一个ts的实例了

ts-node 的安装和使用

我们接着上面的index.ts,我们改写下,改成来打印greeter(user);


/* 创建一个 Student类 */
class Student {
    fullName: string;
    constructor(public firstName: string, public middleInitial: string, public lastName: string) {
        this.fullName = firstName + " " + middleInitial + " " + lastName;
    }
}
/* 创建一个 Person 接口 */
interface Person {
    firstName: string;
    lastName: string;
}

function greeter(person : Person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

let user = new Student("Jane", "M.", "User");

console.log(greeter(user));

然后同样的编译成js

tsc src/index.ts


编译后生成的index.js文件如下:

/* 创建一个 Student类 */
var Student = /** @class */ (function () {
    function Student(firstName, middleInitial, lastName) {
        this.firstName = firstName;
        this.middleInitial = middleInitial;
        this.lastName = lastName;
        this.fullName = firstName + " " + middleInitial + " " + lastName;
    }
    return Student;
}());
function greeter(person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}
var user = new Student("Jane", "M.", "User");
console.log(greeter(user));

然后我们运行该js

node src/index.js

在控制台就会直接打印如下结果:
企业微信截图_16044704149772.png
是不是觉得要运行ts,要先转换成js,再运行js文件,这样效率太低了。
我们可以使用ts-node这个插件来解决这个问题,用这个插件后,就不回编译这么麻烦了,直接使用ts-node就可以看到编译结果了。
首先我们使用npm/cnpm命令来全局安装ts-node

npm install -g ts-node

安装完成后,可以编译index.ts了

ts-node src/index.ts

控制台就会直接打印结果了
企业微信截图_16044708682364.png