【TS01】项目中Typescript配置及编译

2,037 阅读11分钟

前言

本篇主要介绍:

  1. Typescript文件的编译处理。
  2. TypeScript 中的 tsconfig.json 文件的作用、配置参数。

如果一个目录下存在一个 tsconfig.json 文件,那么它意味着这个目录是 TypeScript 项目的根目录。tsconfig.json 文件中指定了用来编译这个项目的根文件和编译选项。 一个项目可以通过以下方式之一来编译:

  • 不带任何输入文件的情况下调用 tsc,编译器会从当前目录开始去查找 tsconfig.json文 件,逐级向上搜索父目录。
  • 不带任何输入文件的情况下调用 tsc,且使用命令行参数 --project(或 -p )指定一个包含 tsconfig.json 文件的目录。

当命令行上指定了输入文件时,tsconfig.json文件会被忽略。

一、TS执行编译

手动编译

指定tsconfig.json

不指定tsconfig.json的情况,会自动获取当前项目根路径下的配置文件。找不到的情况会逐级向上查找。 指定编译配置文件 tsc -p

Typescript使用.ts作为扩展名,想要运行这段代码,需要先编译ts文件中的代码。 tsc greeter.ts 编译后输出一个greeter.js文件,此时就可以执行该段代码了。

自动编译

tsc -w

自动编译存在的问题,增加修改ts文件都会对应输出到编译后指定的文件中,但是,当删除一个ts文件时,并不会上出掉该文件之前已经编译好的对应的js文件,说白了,是“覆盖”

其他执行指令

TSC 的可选项:

  • –project(简写 -p):编译器直接在该目录下查找 tsconfig.json 文件,如果没找到则报错。
  • –build(简写 -b):编译器会进行增量构建。先找到所有引用的工程,然后检查它们是否为最新版本,最后按顺序构建非最新版本的工程。
  • –verbose(简写 -v):打印详细的日志(可以与其它标记一起使用)。
  • –dry: 显示将要执行的操作但是并不真正进行这些操作。
  • –clean: 删除指定工程的输出(可以与–dry一起使用)。
  • –force: 把所有工程当作非最新版本对待。
  • –watch(简写 -w):观察模式。watch 模式监控当前项目 ts 文件变化立即进行编译。

自动编译并执行ts文件

ts-node xxx.ts

现成的依赖,帮我们编译并执行ts文件

二、配置参数

声明文件@types/

当我们直接在项目中引入第三方的模块,并且使用其方法或者是属性,ts 是不会报错的,因为这些类型和方法都是没有进行声明的。因为我们需要使用声明文件来定义这些属性和方法的类型。对于一些常用的第三方模块, typescript 社区已经帮我们定义好了,只要我们在使用 npm 安装模块的时候,在模块名前带上 @types/

npm install express --save// 安装普通的 express 模块
npm install @types/express --save-dev// 安装带有声明文件的 express 模块,只有本地开发环境才进行安装

Common

1. compilerOptions

  • rootDir

用来指定编译文件的根目录,编译器会在根目录查找入口文件。 "rootDir": "./",

  • outDir

指定输出目录
"outFile": "./"

  • rootDirs

可以指定一个路径列表,在构建时编译器会将这个路径中的内容都放到一个文件夹中,通常不配置,用于运行时 "rootDirs": [],

比如 我们创建以下两个文件。

// /util/a.ts 
let a: string = 'A' 
export = a
// /src/index.ts 
import a from './a'

注意在引入 a 时,是引入的当前目录。因为当 rootDirs 设置了 src 和 util 目录时,编译器默认它们属于同级目录。

  • outFile

将多个相互依赖的文件生成一个文件,(文件合并的书序位加载和依赖的顺序)可以用在module为 AMD & System时。
"outFile": "./app.js"

  • baseUrl

设置baseUrl来告诉编译器到哪里去查找模块。所有非相对模块导入都会被当做相对于 baseUrl。有点类似alias。
"baseUrl": "./src",

image.png 原本,一个子文件下引入utils中的工具,引入模块的路径../../../static,配置之后,可以从相对路径引入utils/static

  • paths

模块名到基于 baseUrl的路径映射的列表,是相对于"baseUrl"进行解析。那有的同学有疑问了,vite.resolve.alia不是配置过么? 解释一下,这里配置的paths是为了让ts编译时能够解析对路径。

"paths": {
            "@/*": ["src/*"],
            "views/*": ["src/views/*"],
            "components/*": ["src/components/*"],
            "assets/*": ["src/assets/*"],
            "*": ["src/*"]
        }
  • types

声明文件包,添加要包含的类型声明文件名列表,只有在这里列出的模块的声明文件才会被加载进来。这个也是要关注到的哈,省得一堆波浪线。 如果设置了某一个声明文件,那么编译器只会加载这个声明文件。

  • typeRoots

用来指定声明文件或文件夹的路径列表,如果指定了此项,则只有在这里列出的声明文件才会被加载,通常不配置。声明文件目录,默认 node_modules/@types "typeRoots": [],

  • declarationDir

声明文件的生成的路径 "declarationDir": "./d"


非路径配置输入


  • target

用来指定最终代码运行环境所支持的 JavaScrpt 语法的版本是什么。 "ES5", "ES6"/ "ES2015", "ES2016", "ES2017"或 "ESNext"。 vue3+Vite的技术栈项目中,记得调整为esnext。 默认位ES3
"target": "esnext"

  • module

用来指定编译后模块化代码规范。"None", "CommonJS", "AMD", "System", "UMD", "ES6"或 "ES2015"。只有 "AMD"和 "System"能和 --outFile一起使用。"ES6"和 "ES2015"可使用在目标输出为 "ES5"或更低的情况下。
"module": "UMD"

  • moduleResolution

选择模块解析策略,有“node”和“classic”两种。如果未指定,则 --module commonjs 默认为 Node,否则默认为 Classic(包括 --module 设置为 amd、system、umd、es2015、esnext 等时)。注意:Node 模块解析是 TypeScript 社区中最常用的,推荐用于大多数项目。 如果您在 TypeScript 中遇到导入和导出的解析问题,请尝试设置 moduleResolution: “node” 以查看它是否解决了问题。 "moduleResolution": "node",

  • lib

编译器选项,TS 包含在编译中的库文件,es5 默认 "dom", "es5", "scripthost",例如,我们想在 ts 中使用 es2019 的方法。可以在 lib 配置里添加 es2019
"lib": ["esnext", "dom"],

  • jsx

指定jsx代码用于的开发环境,有“preserve”, "react-native", "react" "jsx": "preserve",

preserve:生成代码中会保留JSX以供后续的转换操作使用(比如:Babel).另外,输出文件会带有.jsx扩展名。 
react:会生成React.createElement,在使用前不需要再进行转换操作了,输出文件的扩展名为.js。 
react-native:相当于preserve,它也保留了所有的JSX,但是输出文件的扩展名是.js
	
模式 			输入 		输出 						输出文件扩展名
preserve 		<div /> 	<div /> 					.jsx
react 			<div /> 	React.createElement("div") 	.js
react-native 	        <div /> 	<div /> 					.js
  • isolatedModules

将导入或者导出的每个文件作为单独的模块。默认为false

  • esModuleInterop

允许 export = 导出,由import = 导入

  • noEmit

不生产编译文件

  • noEmitOnError

发生错误时不输出文件

  • skipLibCheck

忽略所有的声明文件( *.d.ts)的类型检查。这个属性不但可以忽略 npm 不规范带来的报错,还能最大限度的支持类型系统。设置为 true 就不用怕使用的第三方库不规范了。这也算一个难受的点吧,毕竟不是所有的SDK都是规范的ts支持。

  • declaration

用来指定是否在编译的时候生成相的d.ts声明文件,如果设为true,编译每个ts文件之后会生成一个js文件和一个声明文件,但是declaration和allowJs不能同时设为true

  • emitDeclarationOnly

只生成声明文件

  • declarationMap

用来指定编译时是否生成declaration声明文件的.map文件

  • sourceMap

用来指定编译时是否生成目标文件的.map文件 "sourceMap": true,

  • inlineSourceMap

inlineSourceMap指定是否将map文件内容和js文件编译在一个同一个js文件中,如果设为true,则map的内容会以//#soureMappingURL=开头,然后接base64字符串的形式插入在js文件底部 "inlineSourceMap": true,

  • inlineSources

inlineSources用于指定是否进一步将ts文件的内容也包含到输出文件中 "inlineSources": true,

  • sourceRoot

sourceRoot用于指定调试器应该找到TypeScript文件而不是源文件的位置,这个值会被写进.map文件里 "sourceRoot": "",

  • mapRoot

mapRoot用于指定调试器找到映射文件而非生成文件的位置,指定map文件的根路径,该选项会影响.map文件中的sources属性 "mapRoot": "",

  • removeComments

终于指定是否删除编译后文件中的注视

  • allowJs

用来指定是否允许编译JS文件,默认false,即不编译JS文件

  • checkJs

用来指定是否检查和报告JS文件中的错误,默认false


编译语法项


  • strict

用于指定是否启动所有类型检查,如果设为true这回同时开启下面这几个严格检查,默认为false。若 strict 为 true,alwaysStrictnoImplicitAnystrictNullChecksstrictFunctionTypesstrictPropertyInitializationstrictBindCallApplynoImplicitThis 选项默认都为 true。

  • alwaysStrict

指定始终以严格模式检查每个模块,并且在编译之后的JS文件中加入"use strict"字符串,用来告诉浏览器该JS为严格模式

  • noImplicitAny

如果我们没有一些值设置明确类型,编译器会默认认为这个值为any类型,如果将noImplicitAny设为true,则如果没有设置明确的类型会报错,默认值为false,这个从个人经验分析,还是不打开为好。

  • strictNullChecks

当设为true时,不允许把 nullundefined 赋值给其他类型变量。除了any类型,还有个例外就是undefined可以赋值给void类型

  • strictFunctionTypes

用来指定是否使用函数参数双向协变检查

  • strictBindCallApply

设为true后对bind、call和apply绑定的方法的参数的检测是严格检测

function add (a: number, b: number) { return a + b } 
add.call(undefined, 1, '2') 
// Error: Argument of type '"2"' is not assignable to parameter of type 'number'.
  • strictPropertyInitialization

设为true后会检查类的非undefined属性是否已经在构造函数里初始化,如果要开启这项,需要同时开启strictNullChecks,默认为false

  • noImplicitThis

不允许 this 有隐式的 any 类型。

class A { 
    name: string = 'abc' 
    getName () { 
        return function () { 
            console.log(this.name) 
        } 
    }
} 
// Error: 'this' implicitly has type 'any' because it does not have a type annotation.
  • noUnusedLocals

用于检查是否有定义了但是没有使用变量,对于这一点的检测,使用ESLint可以在你书写代码的时候做提示,你可以配合使用,他的默认值为false

  • noUnusedParameters

用于检测是否在函数中没有使用的参数

  • noImplicitReturns

用于检查函数是否有返回值,设为true后,如果函数没有返回值则会提示,默认为false

  • noFallthroughCasesInSwitch

用于检查switch中是否有case没有使用break跳出switch,默认为false

  • allowSyntheticDefaultImports

用来指定允许从没有默认导出的模块中默认导入

  • experimentalDecorators

experimentalDecorators用于指定是否启用实验性的装饰器特性

  • emitDecoratorMetadata

用于指定是否为装上去提供元数据支持,关于元数据,也是ES6的新标准,可以通过Reflect提供的静态方法获取元数据,如果需要使用Reflect的一些方法,需要引用ES2015.Reflect这个库

2. files

编译器需要编译的相对或绝对文件路径的单个文件列表, 这时执行 tsc 命令,编译器会编译 src/index.ts 文件。 "files": [ "src/index.ts" ]

3. include

指定要编译的路径列表, 编译器会编译 指定 目录下的所有 ts 文件。 如果files 和 includes 都没有指定,编译器默认包含当前目录下所有的 ts 文件。 "include":[],

4. exclude

不编译的文件,它也可以指定一个列表,规则和include一样,可以是文件可以是文件夹,可以是相对路径或绝对路径,可以使用通配符' "exclude":[],

5. extends

可以通过指定一个其他的tsconfig.json文件路径,来继承这个配置文件里的配置,继承来的文件的配置会覆盖当前文件定义的配置 "extends":""

6. compileOnSave

设为true,在我们编辑了项目文件保存的时候,编辑器会根据tsconfig.json的配置更新重新生成文本,不过这个编辑器支持

7. references

指定要引用的项目。references属性是 TypeScript 3.0 的新特性,允许将 TypeScript 程序拆分结构化。有点类似组件的思路,避免一个配置文件过于繁琐。分别配置不同的部分,达到更加清晰。 "references": [{ "path": "./tsconfig.node.json" }]

React

Vue

Vue3 + Vite 项目基础配置

# tsconfig.json 

{
    "compilerOptions": {
        "baseUrl": "./",
        "skipLibCheck": true,
        "target": "esnext",
        "module": "esnext",
        "moduleResolution": "node",
        "noImplicitAny": false,
        "strict": true,
        "jsx": "preserve",
        "sourceMap": true,
        "resolveJsonModule": true,
        "esModuleInterop": true,
        "lib": ["esnext", "dom"],
        "types": ["vite/client"],
        "isolatedModules": true,
        "paths": {
            "@/*": ["src/*"],
            "views/*": ["src/views/*"],
            "components/*": ["src/components/*"],
            "assets/*": ["src/assets/*"],
            "*": ["src/*"]
        }
    },
    "include": [
        "src/**/*.ts",
        "src/**/*.d.ts",
        "src/**/*.tsx",
        "src/**/*.vue"
    ],
    "exclude": ["node_modules", "dist"]
}