From 70047ff7b50a085e2151b48750466cdbd0155916 Mon Sep 17 00:00:00 2001 From: Evan Xu <894072666@qq.com> Date: Thu, 8 Oct 2020 22:42:31 +0800 Subject: [PATCH] add note --- .../35.TypeScript\347\254\224\350\256\260.md" | 665 ++++++++++++++++++ 1 file changed, 665 insertions(+) create mode 100644 "docs/01.\345\211\215\347\253\257/40.\345\255\246\344\271\240\347\254\224\350\256\260/35.TypeScript\347\254\224\350\256\260.md" diff --git "a/docs/01.\345\211\215\347\253\257/40.\345\255\246\344\271\240\347\254\224\350\256\260/35.TypeScript\347\254\224\350\256\260.md" "b/docs/01.\345\211\215\347\253\257/40.\345\255\246\344\271\240\347\254\224\350\256\260/35.TypeScript\347\254\224\350\256\260.md" new file mode 100644 index 0000000000..01c0d1116a --- /dev/null +++ "b/docs/01.\345\211\215\347\253\257/40.\345\255\246\344\271\240\347\254\224\350\256\260/35.TypeScript\347\254\224\350\256\260.md" @@ -0,0 +1,665 @@ +--- +title: TypeScript笔记 +date: 2020-10-08 13:02:48 +permalink: /pages/51afd6/ +categories: + - 前端 + - 学习笔记 +tags: + - +--- +# TypeScript 学习笔记 + +TypeScript 的类型校验是给程序员看的,在编译后不会存在TS代码。 + + + +## 类型注解 + +```typescript +function fn(person: string):void{ // 参数类型是字符串,没有返回值 + ///... +} +fn('str') // 如传递参数非字符串,vscode编辑器中或在编译时将给出错误提示 + +const test:number = 1 +``` + + + +### 有哪些基础类型注解? + +``` +// 基础类型 +:string +:number +:boolean + +:null // 只能是null值 +:undefined // 只能是undefined值 + +:symbol + +// 引用类型 +:object // 不常用,多使用接口来给对象进行类型注解 + +// 其他 +:any // 任意类型 +:void // 空,用于函数的无返回值的注解 +:never // 用于标注函数代码永远执行不完(如抛出错误的函数,死循环函数) + + +``` + + + +### 什么是类型注解和类型推断、类型断言? + +**类型注解** 是显式的标注类型 + +**类型推断** 是编辑器根据值来自动推断出类型 (编辑器中鼠标移到变量会显示类型的提示)。 + +**类型断言** 是告诉编译器,“相信我,它就是这个类型”。 + +```js +// 类型注解就是显式的写出类型 +const myNumber: number = 123 + +// 类型推断是根据值来推断类型 (鼠标移到变量会显示类型(或直接显示值)的提示) +const myString = 'test' + +// 类型断言(开发者明确知道是什么类型) +const someValue:any = 'abc' +const strLength:number = (someValue as string).length // 断言someValue是字符串类型 +``` + +### 对象的类型 + +```js +// 对象字面量的类型检查 +const xiaojiejie: { + name: string, + age: number +} = { + name: '小红', + age: 18 +} + +// 标注:object +const obj:object = {} + +// 使用接口 +interface Person{ + name: string + age: number +} +const xjj: Person = { + name: 'xh', + age: 18 +} + +// class类的类型检查 +class Parson { } +const xiaobai: Parson = new Parson() + +// 函数和返回值的类型检查 +const fn: ()=> string = () => '123' +``` + + + +### 函数的类型注解 + +```js +// 函数返回值的类型注解 fn(): number {} +function getTotal2(one: number, two: number): number { + return one + two +} +getTotal2(1,2) + + +// 无返回值: void +function sayHello(): void { + console.log("Hello") +} + +// 永远执行不玩的函数 +function setTimer():never { + throw new Error() + console.log(123) +} + +// 参数是对象时的注解 (也可以用接口) +function add({ one, two }: {one: number, two: number}) { + return one + two +} + +const total = add({one: 1, two: 2}) +``` + + + +### 数组的类型注解 + +```js +const numberArr: number[] = [1, 2, 3] +const stringArr: string[] = ['a', 'b'] +const undefinedArr: undefined[] = [undefined, undefined] +const arr: (number | string | boolean)[] = [1, 'a', true, false] // 用到联合类型 + +// 类型别名 type alias +type lady = { name: string, age: number } + +const xiaojj: lady[] = [ + { + name: 'xiaojj', + age: 90 + }, + { + name: 'j', + age: 30 + } +] + +// 或用类的方式 +class Ady2 { + name: string; + age: number; +} + +const xiaojj2: Ady2[] = [ + { + name: 'xiaojj', + age: 90 + }, + { + name: 'j', + age: 30 + } +] +``` + + + +## 元组 + +元组,可以理解为:**已知元素数量和类型的数组** + +```js +// 联合类型 +const xjj:(string | number)[] = ['a',22,'b'] // 规定整个数组当中可以有string或number + +// 元组注解 注意这里的注解只有一个中括号 +const xjj1: [string, number, number] = ['a', 22, 33] // 规定了数组每个元素对应位置的类型 + +// Note: 在开发中元祖的使用在相对少 + + +// CSV的方式定义数据格式; (二维数组时需要多加一个中括号) +const xjj2: [string, number, number][] = [ + ['a', 22, 33], + ['a', 22, 33] +] + +``` + + + +## 接口 + +接口,可以理解为对象属性的类型描述。和`类型别名`类似,不同的是 接口必须是一个对象,而别名可以直接是一个类型,如` type Girl = string` + +```typescript +interface Girl { // 接口 (理解:对象属性的类型描述) + readonly name: string; // 只读属性 (定义之后不能再修改) + age: number; + waistline?: number; // 加个问号表示是可选值 + [propname: string]: any; // 表示可以有不限制属性名的属性,但属性名需要是字符串,值可以是任意类型 + say(): string; // 函数类型,返回值是string (如无返回值时是 void)。 say()也可以加入参数类型检查,如say(p:number) +} +// 和类型别名类似,不同的是 接口必须是一个对象,而别名可以直接是一个类型,如 type Girl = string + +// 接口的继承 +interface Teacher extends Girl { + teach(): string; +} + + +const girl = { + name: '大脚', + age: 18, + sex: '女', + say() { + return '欢迎光临' + }, + teach() { + return '教' + } +} + + +const screenResume = ({ name, age, bust, sex }: Girl) => { + console.log(name, age, bust, sex) +} +const getResume = ({ name, age, bust, teach}: Teacher) => { + teach(); + console.log(name, age, bust) +} +screenResume(girl) +getResume(girl) + + +// 接口在class类中的使用 +class xiaojjj implements Girl { + name = "xiaojj" + age = 18 + bust = 98 + sex = '女' + say() { + return '欢迎光临' + } +} +``` + +**可索引的类型** + +```js +interface Arr { + [index: number]:string // 表示通过索引访问数据时返回的类型是string +} + +const myArr:Arr = ['1','2','3'] +const myStr:string = myArr[1] +``` + + + + + + + +## ES6 class类中应用TS + +### class类的修饰器 + +```js +// 类的修饰器: +// public (公共) 允许内外部使用 +// protected (受保护的) 允许在内部和继承内使用 +// private (私有) 允许在内部使用,但不能在继承中使用 + +// 类的内部和外部,{}内属于内部,外面是外部 +class Person { + // public 内外都可以使用,可省略,不写时默认public。 protected只允许内部使用 + name: string // 这里的string注释是TS使用的 + private age: 18 + public sayHello() { + console.log(this.name + this.age + 'say hello') + } +} + +class Teacher2 extends Person { + public sayBye() { + console.log(this.name + ' say bye') // protected 可以在继承中使用到 + } +} + +const person = new Person(); +person.name = 'test' // 在类的外部定义 +console.log(person.name) + +``` + +### class类的构造函数中使用类型校验 + +```js +class Person2 { + constructor(public name: string) { + this.name = name + } +} + +class Teacher3 extends Person2{ + constructor(public age: number) { + super('test-name') // 这里传的值是给Person2的构造函数。即使父类没有构造函数,子类的构造函数内也要写super() + } +} +const teacher3 = new Teacher3(18) +console.log(teacher3.name) +console.log(teacher3.age) +``` + +### class类的getter、setter和static + +```js +class Xjj { + constructor(private _age: number) { } + get age() { + return this._age - 10; + } // 访问器属性,以属性的形式访问age,并可以对属性进行包装 + set age(age: number) { + this._age = age+3; + } +} + +const dj = new Xjj(28); +dj.age = 25 + +console.log(dj.age) + + +// 静态属性 static。 静态属性指不需要通过实例化,直接通过Girl.prop的方式就可以访问到属性 +class Girl { + static sayLove() { + return 'I love you' + } +} + +// const girl = new Girl() +console.log(Girl.sayLove()) + +``` + +### class类的只读属性 + +```js +// 只读属性 +class Person { + public readonly _name: string // 只读属性 + constructor(name: string) { + this._name = name; + } +} + +const person = new Person('testName'); +// person._name = '222'; // 不能修改只读属性 +console.log(person._name) +``` + +### 抽象类 + +```js +/ 抽象类 +abstract class Girls { + abstract skill(); // 注意这里只是定义抽象方法,而不具有方法的实现 +} + +class Waiter extends Girls{ // 继承了抽象类之后要 实现抽象类内的成员 + skill() { + console.log('大爷1') + } +} + +class BaseTeacher extends Girls{ + skill() { + console.log('大爷2') + } +} + +class SeniorTeacher extends Girls{ + skill() { + console.log('大爷3') + } +} +``` + + + +## 联合类型和类型保护 + +**联合类型** 指某个参数可以是多种类型。 + +**类型保护** 指参数属于某个类型才有相应的操作。 + +```js +interface Waiter { + anjiao: boolean + say: () => {} +} + +interface Teacher { + anjiao: boolean + skill: () => {} +} + +function judgeWho(animal: (Waiter | Teacher)) { // 联合类型 + // 第一种断言方法 + if (animal.anjiao) { + // (animal as Teacher) 的意思是:断言 animal 是 Teacher类型 + (animal as Teacher).skill() + } else { + (animal as Waiter).say() + } + + // 第二种断言方法 + if ('skill' in animal) { + animal.skill() + } else { + animal.say() + } + + // 第三种类型保护方法是使用typeof来判断 (代码省略) +} + + +class NumberObj { + count: number +} +function addObj(first: object | NumberObj, second: object | NumberObj) { // 联合类型 + if (first instanceof NumberObj && second instanceof NumberObj) { // 类型保护 + return first.count + second.count; + } + return 0; +} + +``` + + + +## 枚举 + +```js +// Enum枚举类型 (个人理解枚举:约定一组可选的常量。 使用常量名表示某个值的含义,增强可读性。) + +// js写法 +// const Status = { +// MASSAGE: 0, +// SPA: 1, +// DABAOJIAN: 2 +// } + +// ts写法 +enum Status { + MASSAGE, // 如果想从1开始,给MASSAGE = 1, 即可 + SPA, + DABAOJIAN +} // 默认赋值 0 、1、2 + +console.log(Status.MASSAGE, Status[0]) // 0, MASSAGE 可以通过下标反查 + +function getStatus(status: any) { + if (status === Status.MASSAGE) { + return 'massage' + } else if (status === Status.SPA) { + return 'spa' + } else if (status === Status.DABAOJIAN) { + return 'dabaojian' + } +} + +const result = getStatus(Status.SPA) +console.log(result) + +``` + + + +## 泛型 + +泛型,最简单的理解:泛指的类型。(类似函数中的形参与实参) + +### 函数中的泛型使用 + +```js + +// function join(first: string | number, second: string | number) { +// return `${first}${second}` +// } +// join('jspang', 1); // 如果我想第一个参数是字符串,第二个也必须是字符串,这么就用到泛型 + + +// 泛型使用,如同定义形参,在调用时指定类型 +function join(first: JSPang, second: JSPang) { + return `${first}${second}` +} + +join('jspang', '123'); +join(11, 22); + +// 泛型中数组的使用 +function myFun(params:ANY[]) { // ANY[] or Array + return params +} +myFun(['a', 'b']) + + +// 两个类型参数的使用(工作中,常用T表示泛型) +function join2(first: T, second: P) { + return `${first}${second}` +} + +join2('jspang', 123); +join2(11, '22'); +join2(11, '22'); // 泛型也支持类型推断 (鼠标移到函数名有提示) + +``` + +### class类中使用泛型 + +```js +// class SelectGirl { +// constructor(private girls: string[] | number[]) { } // private 私有的参数,外部无法修改 +// getGirl(index: number): string | number { +// return this.girls[index] +// } +// } + +// 使用泛型 +class SelectGirl { // 泛型的约束: + constructor(private girls: T[]) { } // private 私有的参数,外部无法修改 + getGirl(index: number): T { + return this.girls[index] + } +} + +// const selectGirl = new SelectGirl(['大脚', 'xiaohong', 'xiaobai']) +const selectGirl = new SelectGirl([101, 102, 103]) +console.log(selectGirl.getGirl(1)) + + +// 泛型中的继承 +interface Girl { + name: string +} +class SelectGirl2 { // 泛型T中必须有一个name属性,继承自Girl接口 + constructor(private girls: T[]) { } // private 私有的参数,外部无法修改 + getGirl(index: number): string { + return this.girls[index].name + } +} + +const selectGirl2 = new SelectGirl2([ + {name: '大脚1'}, + {name: '大脚2'}, + {name: '大脚3'} +]) + +console.log(selectGirl2.getGirl(1)) + +``` + + + + + + + + + +## 配置文件tsconfig.json + +```json +// 此文件由命令 tsc -init 生成 +// 直接运行 tsc 命令就会运用此配置文件 +// 选项详解:https://www.tslang.cn/docs/handbook/compiler-options.html +{ + // "include": ["demo15-1.ts"], // 要编译的指定文件,不配置此项时运行tsc默认编译全部 + // "files": ["demo15-1.ts"], // 和include类似 + // "exclude": ["demo15-3.ts"], // 要排除编译的指定文件 + "compilerOptions": { // 编译选项 + /* 基本选项 */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "module": "commonjs", /* 指定模块代码生成: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + "sourceMap": true, /* 源文件与输出文件的映射关系文件。Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./build", /* 输出的js文件目录。Redirect output structure to the directory. */ + "rootDir": "./src", /* ts源文件目录。Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* 不输出注释到编译结果. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* 严格的类型检查选项 */ + "strict": true, /* 启用所有严格类型检查选项。 打开此选项后,下面这些选项就不需要单独设置*/ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. 为false时允许any不用特意声明。*/ + // "strictNullChecks": true, /* Enable strict null checks. 为false时允许赋值为null*/ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* 附加检查。Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. 报告未使用的本地变量 */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + } +} + +``` + + +