# ts-learn **Repository Path**: gamesgong/ts-learn ## Basic Information - **Project Name**: ts-learn - **Description**: xm-typescript学习,拥抱新技术 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-02-04 - **Last Updated**: 2024-02-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: TypeScript ## README # 起步安装 npm install typescript -g 运行 tsc 文件名 tsc -init 基础类型:Boolean、Number、String、null、undefined 以及 ES6 的 Symbol 和 ES10 的 BigInt # nodejs 环境执行 ts npm i @types/node --save-dev (node 环境支持的依赖必装) npm i ts-node --g ts-node src\index2.ts # tsconfig.json 1.include 指定编译文件默认是编译当前目录下所有的 ts 文件 2.exclude 指定排除的文件 3.target 指定编译 js 的版本例如 es5 es6 4.allowJS 是否允许编译 js 文件 5.removeComments 是否在编译过程中删除文件中的注释 6.rootDir 编译文件的目录 7.outDir 输出的目录 8.sourceMap 代码源文件 9.strict 严格模式 10.module 默认 common.js 可选 es6 模式 amd umd 等 在 CommonJS 中,你可以使用 module.exports 或 exports 来导出对象、函数或值。 const common = require('./common.js'); 你可以使用 typeRoots 和 types 属性来指定类型库。 当你想要指定一个类型库的入口点,你可以使用 typeRoots。 ``` "compilerOptions": { "incremental": true, // TS编译器在第一次编译之后会生成一个存储编译信息的文件,第二次编译会在第一次的基础上进行增量编译,可以提高编译的速度 "tsBuildInfoFile": "./buildFile", // 增量编译文件的存储位置 "diagnostics": true, // 打印诊断信息 "target": "ES5", // 目标语言的版本 "module": "CommonJS", // 生成代码的模板标准 "outFile": "./app.js", // 将多个相互依赖的文件生成一个文件,可以用在AMD模块中,即开启时应设置"module": "AMD", "lib": ["DOM", "ES2015", "ScriptHost", "ES2019.Array"], // TS需要引用的库,即声明文件,es5 默认引用dom、es5、scripthost,如需要使用es的高级版本特性,通常都需要配置,如es8的数组新特性需要引入"ES2019.Array", "allowJS": true, // 允许编译器编译JS,JSX文件 "checkJs": true, // 允许在JS文件中报错,通常与allowJS一起使用 "outDir": "./dist", // 指定输出目录 "rootDir": "./", // 指定输出文件目录(用于输出),用于控制输出目录结构 "declaration": true, // 生成声明文件,开启后会自动生成声明文件 "declarationDir": "./file", // 指定生成声明文件存放目录 "emitDeclarationOnly": true, // 只生成声明文件,而不会生成js文件 "sourceMap": true, // 生成目标文件的sourceMap文件 "inlineSourceMap": true, // 生成目标文件的inline SourceMap,inline SourceMap会包含在生成的js文件中 "declarationMap": true, // 为声明文件生成sourceMap "typeRoots": [], // 声明文件目录,默认时node_modules/@types "types": [], // 加载的声明文件包 "removeComments":true, // 删除注释 "noEmit": true, // 不输出文件,即编译后不会生成任何js文件 "noEmitOnError": true, // 发送错误时不输出任何文件 "noEmitHelpers": true, // 不生成helper函数,减小体积,需要额外安装,常配合importHelpers一起使用 "importHelpers": true, // 通过tslib引入helper函数,文件必须是模块 "downlevelIteration": true, // 降级遍历器实现,如果目标源是es3/5,那么遍历器会有降级的实现 "strict": true, // 开启所有严格的类型检查 "alwaysStrict": true, // 在代码中注入'use strict' "noImplicitAny": true, // 不允许隐式的any类型 "strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量 "strictFunctionTypes": true, // 不允许函数参数双向协变 "strictPropertyInitialization": true, // 类的实例属性必须初始化 "strictBindCallApply": true, // 严格的bind/call/apply检查 "noImplicitThis": true, // 不允许this有隐式的any类型 "noUnusedLocals": true, // 检查只声明、未使用的局部变量(只提示不报错) "noUnusedParameters": true, // 检查未使用的函数参数(只提示不报错) "noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即如果没有break语句后面不会执行) "noImplicitReturns": true, //每个分支都会有返回值 "esModuleInterop": true, // 允许export=导出,由import from 导入 "allowUmdGlobalAccess": true, // 允许在模块中全局变量的方式访问umd模块 "moduleResolution": "node", // 模块解析策略,ts默认用node的解析策略,即相对的方式导入 "baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录 "paths": { // 路径映射,相对于baseUrl // 如使用jq时不想使用默认版本,而需要手动指定版本,可进行如下配置 "jquery": ["node_modules/jquery/dist/jquery.min.js"] }, "rootDirs": ["src","out"], // 将多个目录放在一个虚拟目录下,用于运行时,即编译后引入文件的位置可能发生变化,这也设置可以虚拟src和out在同一个目录下,不用再去改变路径也不会报错 "listEmittedFiles": true, // 打印输出文件 "listFiles": true// 打印编译的文件(包括引用的声明文件) } // 指定一个匹配列表(属于自动指定该路径下的所有ts相关文件) "include": [ "src/**/*" ], // 指定一个排除列表(include的反向操作) "exclude": [ "demo.ts" ], // 指定哪些文件使用该配置(属于手动一个个指定文件) "files": [ "demo.ts" ] ``` # 模块化 Commonjs - > Nodejs // 导入 require("xxx"); require("../xxx.js"); // 导出 exports.xxxxxx= function() {}; module.exports = xxxxx; ## AMD -> requireJs // 定义 define("module", ["dep1", "dep2"], function(d1, d2) {...}); // 加载模块 require(["module", "../app"], function(module, app) {...}); ## CMD -> seaJs define(function(require, exports, module) { var a = require('./a'); a.doSomething(); var b = require('./b'); b.doSomething(); }); ## UMD -> UMD 是 AMD 和 CommonJS 的糅合 (function (window, factory) { // 检测是不是 Nodejs 环境 if (typeof module === 'object' && typeof module.exports === "objects") { module.exports = factory(); } // 检测是不是 AMD 规范 else if (typeof define === 'function' && define.amd) { define(factory); } // 使用浏览器环境 else { window.eventUtil = factory(); } })(this, function () { //module ... }); ## es6 模块化规范出来之后上面这些模块化规范就用的比较少了 现在主要使用 import export es6 模块化规范用法 .1.默认导出 和 引入 默认导出可以导出任意类型,这儿举例导出一个对象,并且默认导出只能有一个 引入的时候名字可以随便起 //导出 export default { a:1, } //引入 import test from "./test"; 2.分别导出 export default { a:1, } export function add(a: T, b: T) { return a + b } export let xxx = 123 //引入 import obj,{xxx,add} from './test' 3.重名问题 如果 导入的时候叫 add 但是已经有变量占用了可以用 as 重命名 import obj,{xxx as bbb,add} from './test' console.log(bbb) 4.动态引入 import 只能写在顶层,不能掺杂到逻辑里面,这时候就需要动态引入了 if(true){ import('./test').then(res => { console.log(res) }) } ## d.ts 声明文件 declare 使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能 declare var 声明全局变量 declare function 声明全局方法 declare class 声明全局类 declare enum 声明全局枚举类型 interface 和 type 声明全局类型 declare namespace 声明(含有子属性的)全局对象 export 导出变量 export default ES6 默认导出 export = commonjs 导出模块 export as namespace UMD 库声明全局变量 declare global 扩展全局变量 declare module 扩展模块 /// 三斜线指令 你列出了 TypeScript 中的几个声明相关的关键词,我会为你逐一解释它们之间的区别。 1. **declare var**: * 当你使用 `declare var`,你告诉 TypeScript 编译器某个变量已经存在,但它的类型还未被声明。这常用于全局变量或者第三方库提供的变量。 * 例如,假设有一个全局变量 `window.someGlobalVar`,你可以使用 `declare var someGlobalVar: any;` 来告诉 TypeScript 这个变量存在,但它的类型是不确定的。 2. **declare namespace**: * 当你想声明一个全局对象,这个对象含有子属性或子对象时,你可以使用 `declare namespace`。这常用于第三方库或全局对象。 * 例如,`declare namespace SomeLibrary { property: string; }` 会声明一个名为 `SomeLibrary` 的全局对象,并为其添加一个名为 `property` 的属性。 3. **declare global**: * `declare global` 是用来扩展全局作用域的。当你在一个模块内部使用 `declare global`,你告诉 TypeScript 编译器这个模块是在全局作用域中运行的。这常用于 UMD 模块或与浏览器环境相关的模块。 * 使用 `declare global` 可以帮助 TypeScript 编译器理解模块如何与全局作用域交互,例如 `window` 对象。 4. **declare module**: * 这个关键词并不是 TypeScript 的标准关键字。可能你是想表达的是 `declare namespace` 或其他相关概念。确保你准确地描述了你想要的内容。 5. **/// **: * 三斜线指令(Triple-Slash Directives)是 TypeScript 的特殊注释,用于引入其他文件或模块。例如,`/// ` 会告诉 TypeScript 编译器去包含另一个文件 `anotherFile.ts`。这主要用于解决类型声明和模块之间的依赖关系。 * 需要注意的是,随着 TypeScript 的发展,很多旧的工具和构建系统(如 `tsd`)仍然使用这些三斜线指令,但在较新的项目中,你可能更倾向于使用 `import` 或其他现代的模块导入方法。 希望这些解释能帮助你更好地理解这些关键词和指令的区别! ## 类型声明 ts 会解析项目中所有的 _.ts 文件,当然也包含以 .d.ts 结尾的文件。 所以当我们将 jQuery.d.ts 放到项目中时,其他所有 _.ts 文件就都可以获得 jQuery 的类型定义了。 假如仍然无法解析,那么可以检查下 tsconfig.json 中的 files、include 和 exclude 配置,确保其包含了 jQuery.d.ts 文件。 与该 npm 包绑定在一起。判断依据是 package.json 中有 types 字段, 或者有一个 index.d.ts 声明文件。这种模式不需要额外安装其他包, 是最为推荐的,所以以后我们自己创建 npm 包的时候, 最好也将声明文件与 npm 包绑定在一起。 **发布到 @types 里。我们只需要尝试安装一下对应的 @types 包就知道是否存在该声明文件,** **安装命令是 npm install @types/foo --save-dev。** 这种模式一般是由于 npm 包的维护者没有提供声明文件,所以只能由其他人将声明文件发布到 @types 里了 假如以上两种方式都没有找到对应的声明文件, 那么我们就需要自己为它写声明文件了。 由于是通过 import 语句导入的模块,所以声明文件存放的位置也有所约束,一般有两种方案: 创建一个 node_modules/@types/foo/index.d.ts 文件, 存放 foo 模块的声明文件。这种方式不需要额外的配置, 但是 node_modules 目录不稳定,代码也没有被保存到仓库中,无法回溯版本, 有不小心被删除的风险,故不太建议用这种方案,一般只用作临时测试。 创建一个 types 文件夹,专门用来管理自己写的声明文件, 将 foo 的声明文件放到 types/foo/index.d.ts 中。 这种方式需要配置下 tsconfig.json 中的 paths 和 baseUrl 字段。 { "compilerOptions": { "module": "commonjs", "baseUrl": "./", "paths": { "*": ["types/*"] } } } # include 、exclude、files的不同 “include” : [“demo.ts”] 指定编译的文件,目录 “exclude” : [ “demo.ts”] 指定不编译的文件,目录 “files” : [“demo.ts”] 指定编译的文件 ,目录 不同: include包含的文件会被exclude排除编译 files包含的文件不会被exclude排除编译 # paths 路径重映射。 要使用 paths,首先要设置好 baseUrl,paths 的源路径和新路径会使用 baseUrl 作为相对路径计算。 "baseUrl": "./src", "paths": { "@lib/*": ["./other/_lib/*", "./other/_lib2/*"] }, 上面的配置,是将 other/_lib 和 other/_lib2 路径重映射为 @lib。 这里的 @ 并不是必须的,这样写只是表明这个路径是一个重映射,或者叫别名,实际上文件系统上不存在对应的真实目录。 这样,原来比较冗长的路径: import LibA from "other/_lib/lib_a"; 就可以改为: import LibA from "@lib/lib_a"; # types 类型声明的一种引入方式是 @types 包,比如 React 框架使用了 flow 作为类型系统,为了支持 TypeScript,React 团队又写一套 d.ts 类型文件,发布到 @types/react 包上。 然后我们下载这个类型包后,并使用类似 import React from 'react',TS 会从从 node_modules/@types 中找到 react 文件夹,如果找不到,就会向上一层目录继续找,知道找到位置。如果存在,这个 React 对象就会被赋予声明的类型。 @types 可以是模块类型声明(像 React 类型),也可以是全局类型声明(如 nodejs 的 process 对象类型)。 types 配置 可指定只使用哪些全局类型声明,而不是 node_modules/@types 下所有的类型声明。 # `typeRoots` 和 `types` 是 TypeScript 配置中的两个属性,它们用于引入第三方模块的类型声明。 1. **typeRoots**: * 它是一个路径数组,告诉 TypeScript 在哪里查找类型声明文件。当你在代码中导入一个模块并希望使用它的类型声明时,TypeScript 需要知道去哪里查找这些类型声明。`typeRoots` 就是告诉 TypeScript 去哪些文件夹下查找这些类型声明文件的。 * 例如,如果你安装了一个 npm 包,并且这个包有一个类型声明文件,你可以通过将 npm 包的目录添加到 `typeRoots` 中来告诉 TypeScript 在哪里查找这个类型声明文件。 2. **types**: * 这是一个字符串数组,用于明确指定应该包含哪些类型声明文件。当你知道某个类型声明文件是必需的,但 TypeScript 编译器可能不会自动包含它时,你可以使用这个属性来明确指定它。 * 例如,如果你正在使用某个特定的第三方库,并且这个库的类型声明文件没有被默认包含,你可以通过将库的类型声明文件名添加到 `types` 中来确保它被包含在编译中。 这两个属性通常用于引入第三方模块的类型声明,以确保在编译和运行 TypeScript 代码时能够正确地识别和使用这些模块的类型。