TypeScript

微软公司, 设计的 TypeScript

TS是什么 ?

出现的目的: 解决 JS 出现的一些问题, TS 是以 JS 为 基础构建的语言,是一个JS的超集

TS 完全支持,兼容JS, 给动态的JS变量类型, 设置为静态的变量类型。 主要是加上了 Type

TS特点

  • TypeScript 扩展了 JS, 并添加了类型
  • 可以在任何支持JS的平台中执行
  • TS不能被JS解析器直接执行, 需要将 TS 编译为 JS文件

增加了类型

变量

ts 的变量

  1. Ts 的变量声明
  1. // 1. Ts 的变量声明
  2. let a:number;
  3. // a 的类型设置为了 Number, 在以后的使用过程中 a 的值只能是 number 类型
  4. a = 10;
  5. a = 33;
  6. // a = 'hello'; // 这里直接报错了,不能赋值为 字符串 , 默认情况下,ts 会报错了,依旧会被编译为js文件
  1. 可以使用 | 来 连接多个类型 (联合类型)
  1. // let c: 'male' | 'female'
  2. let c: boolean | string; // c 可以是 boolean 类型, 也可以是 string 类型
  3. c = true
  4. c = 'true'
  1. any 类型
  1. // 一个变量设置类型为 any 后,相当于对该变量关闭了Ts的类型检测
  2. // let d:any; // any 可以是任以类型 - 显示类型
  3. // 同样 直接声明 d,没有确定类型, 它的类型也是 any
  4. let d; // 默认类型为 any - 声明变量,不指定类型, ts 解析器 自动判断类型为 any (隐式类型)
  5. d = 12;
  6. d = 'abc';
  7. d = false;
  8. d = [1, 2, 3];
  9. // any 的缺点, 会污染其他类型变量
  10. // 例如
  11. let s: string;
  12. s = d; // 不会报错, s 赋值为 d ; d 此时是一个 [] , 而 s 则为 string
  13. // s 出现变量被污染 -> any 的缺点
  1. unknown 表示位置的值
  1. // 4. unknown 表示位置的值
  2. let e: unknown;
  3. e = 10;
  4. e = 'hello';
  5. // s = e; // 这里会报错, e 的类型不确定 s -> String, e -> unknown
  6. // unknown 实际上就是一个类型 安全的 any
  7. // unknown 类型的变量, 不能直接赋值给其他变量 -> 需要类型判断
  8. if (typeof e === 'string') {
  9. s = e; // 这样就不会报错
  10. }
  1. 类型断言 :直接告诉编译器 xxx 类型就是 xx 类型 实际类型
  1. // 5.
  2. // 类型断言 :直接告诉编译器 xxx 类型就是 xx 类型 实际类型
  3. s = e as string; // x as 类型
  4. // 第二种写法
  5. s = <string>e;
  6. /**
  7. * 语法
  8. * 1. xx as <类型>
  9. * 2. <类型>xx
  10. */
  1. void 用来表示没有返回值
  1. // 以函数为例
  2. function fn(): void {
  3. // 1. 不写return
  4. // 2. return; return 为空值
  5. // 3. return undefined | null 。 都表示为空
  6. // 4. return 123 // 会报错
  7. }
  1. never 表示永远不会返回结果,
  1. // 7. never 表示永远不会返回结果,
  2. function fn2(): never {
  3. throw new Error('报错了')
  4. }

引用类型的变量

  1. object ```typescript // 1. Ts 的 object

let a:object; // object 表示一个对象

a = {}; a = function () {}; // function 也是一个对象

// a:object 不是很实用, 因为JS中 object 的类型数据实在太多了

  1. <br />使用 `type` 自定义
  2. 2. _{} 用来指定对象中可以包含哪些属性_
  3. ```typescript
  4. // 2. {} 用来指定对象中可以包含哪些属性
  5. // 语法: {属性名: 属性值}
  6. // 在属性后面加上 ? 表示属性是可选的
  7. let b: {name: string, age?: number};
  8. // b = {name: "Yellowsea"};
  9. // b = {name: "123", age: 123}; // 报错,必须按照 b 定义的方式,多一个少一个都不行
  10. // 在 加上 age? 后
  11. b = {name: "Yellowsea", age:123};
  12. b = {name: "Yellowsea"}; // 都是可以的
  13. // 定义任意多个类型的属性
  14. // [propName: string]: any 表示任意类型的属性 propName: 属性名-> string 属性值 :any
  15. let c: {name: string, [propName: string]: any}; // 常用的语法
  16. c = {name: "Yellowsea", age:123, sex: '男'} // 这样写多个属性
  17. // 2. 设置函数结构的类型声明
  18. // 语法: (形参:类型, 形参:类型...)=> 返回值
  19. // 设置 d 为一个函数,a,b 都是参数, 返回值是 num 类型
  20. let d:(a:number, b:number) => number; // 用来定义函数的结构 -> 常用的语法
  21. d = function (n1, n2) { // n1, n2 对应 a,b 。 多一个少一个都不行
  22. return n1 + n2
  23. }
  1. array 数组 ```typescript // 3. array 数组 // Ts定义 数组的语法: /**
      • 类型[]
      • Array<类型> */

// string[] 表示字符串数组 let e:string[];

e = [‘a’,’b’, ‘c’]; // good // e = [‘1’, ‘2’, 3]; // bad

// number[] 表示数值数组 let f:number[];

// 或者 let g: Array; // 也表示存储Number 类型的数组 g = [1,2,3];

  1. 4. _元组,元组就是固定长度的数组_
  2. ```typescript
  3. /**
  4. * 4. 元组,元组就是固定长度的数组
  5. * 定义元组: let h: [string, string];
  6. * - 语法: [类型, 类型, 类型]
  7. */
  8. // 定义元组,
  9. let h: [string, string]; // 固定两个长度的 string 类型
  10. h = ["hello", "abc"]; // good
  11. // h = [1, "1"] // bad
  1. enum 枚举 ```typescript /**
      1. enum 枚举
      • Ts 语法特有的 */

// 普通定义数据时 设置性别为 0 | 1 // let i: {name: string, gender: 0 | 1};

// i = { // name: ‘Yellowsea’, // gender: 0 // }

// 但是这样定义会出现问题,当用户使用时,不知道 0 | 1 是什么、

// 使用枚举 enum Gender { // 定义枚举 // 不需要知道枚举的内容是什么 Male, Female }

// 使用枚举 let i: {name: string, gender: Gender}; // gender 使用 枚举, Gender

i = { name: ‘Yellowsea’, // gender: Gender.Male gender: Gender.Female, // 这是好的定义 }

console.log(i.gender == Gender.Male);

  1. 6. _补充内容_
  2. ```typescript
  3. // 6. 补充内容
  4. // | 或
  5. // let j: string | number; // j 的类型是 string 或 number 类型
  6. // j = "hello" | j = 123
  7. // & 与
  8. // let j: {name: string} | {age: number}
  9. let j: {name: string} & {age: number}
  10. j = {name: 'yellowsea', age: 123};

tsconfig配置选项

使用 tsc --init 进行 初始化 , 会自动创建 tsconfig.json 文件

include

include 编译指定目录下的需要编译的文件

  1. {
  2. /**
  3. include
  4. 配置ts编译器,编译指定目录下的需要编译的文件
  5. 写在 tsconfig.json 的最外侧
  6. 路径: ** 表示任意目录
  7. * 表示任意文件
  8. */
  9. // 编译指定目录下的需要编译的文件
  10. "include": [
  11. "./src/**/*"
  12. ],
  13. }

exclude

_exclude_ : 需要排除编译的文件

  1. {
  2. /**
  3. exclude : 需要排除编译的文件
  4. // 它是可选的, 具有默认值: ["node_modules", "bower_components", "jspm_packages"]
  5. */
  6. "exclude": [
  7. // 不让 hello 文件夹下的文件被编译
  8. "./src/hello/*"
  9. ],
  10. }

extends

_extends_ 继承 配置

  1. {
  2. /*
  3. extends 继承 配置。
  4. - 比如你还有另一个 xxx.json 的配置文件,可以通过 extends 引入进来
  5. - 相当于 合并两个文件的配置
  6. - 这里不演示
  7. - 语法: "extends": "./configs/base"
  8. */
  9. "extends": "./configs/base.json",
  10. }

file

_file_ 表示需要编译的单个文件, 需要列举出来

  1. {
  2. /*
  3. flies : 文件。 include 类似,
  4. - 表示需要编译的单个文件, 需要列举出来
  5. 语法:
  6. files: [
  7. "./fileName.ts",
  8. ...
  9. ]
  10. // base.json 配置 files
  11. */
  12. }

compilerOptions

_compilerOptions_“ 编译器的选项, 在 tsconfig.json 中最重要的配置

学习配置ts , 也就是 学习配置 compilerOptions , 学会它的 子选项的配置

这里的配置项基本上都有自己的默认值,如果需要配置某个配置, 设置一个错误的值,编译后出错,可以看到所有的选项

1. target

  1. // ts 编译器的选项
  2. "compilerOptions": {
  3. //1. target 用来指定 ts 文件被编译为 ES 的版本
  4. // 默认TS会转为 ES3 版本, 兼容行好
  5. // target: 的属性值 :
  6. // 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'es2021', 'es2022', 'esnext'.
  7. "target": "es6",
  8. }

2. module

  1. "compilerOptions": {
  2. //2. module 指定要使用的模块化的规范
  3. // module的属性值: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'es2022', 'esnext', 'node12', 'nodenext'
  4. "module": "commonjs",
  5. }

3. lib

  1. "compilerOptions": {
  2. //3. lib 用来指定项目中要用到的库 - 浏览器运行环境
  3. // 一般不去动它,也不用去配置,如果写了, 什么都不配置,表示没有使用任何库, 然后写TS代码时候,没有任何补全
  4. // 它的属性值很多,在写 lib: xx 让它报错,然后可以查看它的属性值
  5. // "lib": ["DOM", "ES2015"]
  6. }

4. outDir

  1. "compilerOptions": {
  2. //4. outDir 用来指定编译后文件所在的目录
  3. // 表示 编译TS文件后 生成 JS文件存放的目录, 将源码 生成的目录分开
  4. "outDir": "./dist",
  5. }

5. outFile

  1. "compilerOptions": {
  2. // 5. outFile 将代码合并为一个文件
  3. // 设置 outFile 后,所有的全局作用域中的代码 会合并到同一个文件中
  4. // "outFile": "./dist/app.js", // 使用时 module 需要改为 system
  5. // 用的不多, 一把结合打包工具使用
  6. }

6. allowJs

  1. "compilerOptions": {
  2. // 6. allowJs 是否 JS文件进行编译, 默认 false
  3. // 改为true 后,同样编译 src 目录下的 js 文件
  4. // "allowJs": false,
  5. "allowJs": true, // 一般用在项目中,不得不使用的第三方库, js 文件的编译
  6. }

7. checkJs

  1. "compilerOptions": {
  2. // 7. checkJs 是否检查js代码是否符合语法规范, 默认值为 false
  3. // "checkJs": false, // 不检查js的语法
  4. "checkJs": true, // allowJs 具有冲突,一般使用它们之间的其中一个
  5. }

8. removeComments

  1. "compilerOptions": {
  2. // 8. removeComments : 在编译ts中, 是否移除注释 , 默认为false
  3. "removeComments": true,
  4. }

9. noEmit

  1. "compilerOptions": {
  2. // 9. noEmit 不生成编译后的文件, 默认为false
  3. // "noEmit": false
  4. // "noEmit": true, // 不常用
  5. }

10. noEmitOnError

  1. "compilerOptions": {
  2. // 10. noEmitOnError : 当有错误时候 不生成 编译后的文件, 默认为 false
  3. "noEmitOnError": true,
  4. }

11. strict

TS 的语法检查 选项

  1. "compilerOptions": {
  2. // 接下来就是 TS 的语法检查 选项
  3. // strict : Ts 语法检查的总开关, 默认为 false,
  4. "strict": true, // 项目中都会打开,这样代码出错的比较少
  5. }

alwaysStrict

  1. "compilerOptions": {
  2. // 接下来就是 TS 的语法检查 选项
  3. // strict : Ts 语法检查的总开关, 默认为 false,
  4. "strict": true, // 项目中都会打开,这样代码出错的比较少
  5. // 11. alwaysStrict 用来设置编译后的文件是否使用 严格模式, 默认为 false
  6. "alwaysStrict": true, // 编译生成的 JS文件, 会加上 严格模式 : "use strict";
  7. }

noImplicitAny

  1. "compilerOptions": {
  2. // 接下来就是 TS 的语法检查 选项
  3. // strict : Ts 语法检查的总开关, 默认为 false,
  4. "strict": true, // 项目中都会打开,这样代码出错的比较少
  5. // 12. noImplicitAny : 是否允许隐式的 any 类型 , 默认是false
  6. "noImplicitAny": true,
  7. }

noImplicitThis

  1. "compilerOptions": {
  2. // 接下来就是 TS 的语法检查 选项
  3. // strict : Ts 语法检查的总开关, 默认为 false,
  4. "strict": true, // 项目中都会打开,这样代码出错的比较少
  5. // 13. noImplicitThis : 是否允许 不明确类型的 this , 默认值为 false;
  6. "noImplicitThis": true,
  7. }

strictNullChecks

  1. "compilerOptions": {
  2. // 接下来就是 TS 的语法检查 选项
  3. // strict : Ts 语法检查的总开关, 默认为 false,
  4. "strict": true, // 项目中都会打开,这样代码出错的比较少
  5. // 14. strictNullChecks :严格检查空值
  6. "strictNullChecks": true,
  7. }

webpack + TS

项目初始化

  1. mkdir webpack-ts && cd webpack-ts
  2. npm init -y
  3. tsc --init
  4. mkdir src && cd src && touch index.ts
  5. touch webpack.config.js
  1. // 安装的依赖
  2. npm install -D \
  3. ts-loader \
  4. typescript \
  5. webpack \
  6. webpack-cli \
  7. webpack-dev-server \
  8. html-webpack-plugin \
  9. core-js \
  10. @babel/core \
  11. @babel/preset-env \
  12. babel-loader \

源代码

src/index.ts

  1. // 省略了 m 的扩展名
  2. import { name } from "./m"
  3. console.log("Hello webpack+Ts");
  4. let div = document.createElement('div');
  5. // const box = document.querySelector('#box');
  6. if (div !== null) {
  7. div.innerHTML = `<h1>Hello Webpack + Ts </h1>`
  8. }
  9. document.body.append(div);
  10. // 写好的TS代码
  11. function sum (a: number, b: number): number {
  12. return a + b;
  13. }
  14. console.log(sum(1,2));
  15. console.log(sum(123, 456));
  16. console.log(sum(123, 777));
  17. console.log(name);
  18. // m.ts
  19. export const name = "yellowsea";
  20. let num = 123;
  21. num = 10;
  22. console.log(num);

src/index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>webpack + Ts</title>
  8. </head>
  9. <body>
  10. </body>
  11. </html>

配置项

package.json

  1. {
  2. "scripts": {
  3. "test": "echo \"Error: no test specified\" && exit 1",
  4. "build": "webpack",
  5. "start": "webpack serve --open"
  6. },
  7. }

tsconfig.json

  1. {
  2. // ts 编译器的配置
  3. "compilerOptions": {
  4. // 也可以使用 commonjs
  5. "module": "ES6",
  6. "target": "ES6",
  7. "strict": true,
  8. "sourceMap": true, // 编译后的文件出错时, 回溯源代码的所在的位置的映射
  9. }
  10. }

wbepack.config.js

  1. const path = require('path');
  2. const HtmlWebpackPlugin = require('html-webpack-plugin');
  3. module.exports = {
  4. // mode: 'development',
  5. mode: 'production',
  6. entry: {
  7. index: './src/index.ts',
  8. },
  9. output: {
  10. filename: 'bundle.js',
  11. path: path.resolve(__dirname, 'dist'),
  12. clean: true
  13. },
  14. //
  15. module: {
  16. rules: [
  17. // 规则
  18. {
  19. test: /\.ts$/,
  20. use: [
  21. // 配置babel
  22. {
  23. loader: 'babel-loader',
  24. // 配置babel
  25. options: {
  26. // 设置预定的环境
  27. presets: [
  28. [
  29. // 指定的环境
  30. "@babel/preset-env",
  31. // 配置信息
  32. {
  33. // 要兼容的浏览器
  34. targets: {
  35. "chrome": "58",
  36. "ie": "11"
  37. },
  38. // 指定corejs 的版本
  39. "corejs": "3",
  40. // 使用 corejs 的方式, "usage" 表示按需加载
  41. "useBuiltIns": "usage"
  42. }
  43. ]
  44. ]
  45. }
  46. },
  47. 'ts-loader'
  48. ],
  49. exclude: /node_modules/
  50. }
  51. ]
  52. },
  53. plugins: [
  54. new HtmlWebpackPlugin({
  55. title: 'webpack + ts',
  56. template: './src/index.html'
  57. })
  58. ],
  59. resolve: {
  60. // 省略引入的扩展名
  61. extensions: ['.js', '.jsx', '.ts']
  62. }
  63. }
  64. /**
  65. * {
  66. * loader: 'babel-loader',
  67. * presets: [
  68. * "@babel/preset-env"
  69. * ]
  70. * }
  71. */

TS 类

TS 的类和JS类基本一样,都是使用 class 关键字

类中包含主要两部分

  • 属性
  • 方法
  1. class Person {
  2. // 定义属性 - 在 class 内的 叫做实例属性 - 需要通过 实例去访问
  3. name:string = 'Yellowsea';
  4. // 加上 readonly 后 只能读, 不能修改
  5. readonly age:number = 123;
  6. // 在属性前 使用 static 关键字 可以定义 类属性, 叫做静态属性
  7. // 静态属性: 定义类时, 不用创建实例,通过类名,能够访问到的属性
  8. static test:string = '这是static test'
  9. // 定义方法 --- 实例方法
  10. sayHello() {
  11. console.log("Hello")
  12. }
  13. // 静态方法
  14. static sayHello2() {
  15. console.log("Hello2")
  16. }
  17. }
  18. const p = new Person();
  19. console.log(p);
  20. console.log(p.age);
  21. console.log(p.name);
  22. // 通过实例修改 实例属性
  23. p.name = 'Hidie'
  24. console.log(p.name);
  25. // p.age = 123123; // readonly ,修改不了
  26. // console.log(Person.age); // 访问不到 age
  27. console.log(Person.test); // 能够访问到test
  28. Person.test = "testtest"; // 可以修改, 静态属性加上 readonly 后也修改不了
  29. console.log(Person.test);
  30. // 通过实例调用 方法
  31. p.sayHello();
  32. // 加上 static 方法名 , 静态方法
  33. Person.sayHello2();

类的构造函数

  1. class Dog {
  2. // TS 需要在类中 提前定义 name age 并赋予类型
  3. name: string;
  4. age: number;
  5. // 构造函数 constructor
  6. // 构造函数 是在new XXX 的时候, 传递参数,在构造函数中能够获取得到 参数
  7. constructor(name:string, age:number) {
  8. // 在 new XXX 的 时候执行 , 此时的 this 就表示当前的的 实例
  9. // console.log("constructor执行了", this)
  10. this.name = name;
  11. this.age = age;
  12. // console.log(this)
  13. }
  14. bark() {
  15. // 这里的 this 表示 当前调用方法的对象
  16. console.log("bark", this)
  17. }
  18. }
  19. const dog = new Dog("小黑", 123);
  20. const dog2 = new Dog("小白", 123);
  21. dog.bark();
  22. dog2.bark();

继承

  1. // 将所有的 变量 写在 这个作用域里
  2. // class Dog {
  3. // name: string;
  4. // age: number;
  5. // constructor(name:string, age:number) {
  6. // this.name = name;
  7. // this.age = age;
  8. // }
  9. // sayHello () {
  10. // console.log('wangwanga')
  11. // }
  12. // }
  13. // class Cat {
  14. // name: string;
  15. // age: number;
  16. // constructor(name:string, age:number) {
  17. // this.name = name;
  18. // this.age = age;
  19. // }
  20. // sayHello () {
  21. // console.log('wangwanga')
  22. // }
  23. // }
  1. // 因为在学习ts过程中, ts 会检查当前目录的所有变量, 当变量名相同 就会报错
  2. // 使用 立即执行函数 解决
  3. (function () {
  4. class Animal {
  5. name: string;
  6. age: number;
  7. constructor(name:string, age:number) {
  8. this.name = name;
  9. this.age = age;
  10. }
  11. sayHello (call:string) {
  12. console.log(call)
  13. }
  14. }
  15. // 使用 extend 关键字 继承 父类的 方法 和 属性
  16. class Dog extends Animal {
  17. // Dog 类 本身自己的方法
  18. run () {
  19. console.log(this.name, "在跑````")
  20. }
  21. }
  22. class Cat extends Animal {
  23. // 修改父类的 sayHello 方法
  24. sayHello() {
  25. console.log(this.name, "miaomiaoamia asdsadasd")
  26. }
  27. }
  28. const dog = new Dog("旺财", 123);
  29. dog.sayHello("wangwangawang");
  30. dog.run();
  31. const cat = new Cat('咪咪', 123123);
  32. cat.sayHello();
  33. //
  34. })()

super

  1. // super 关键字
  2. (function () {
  3. class Animal {
  4. name: string;
  5. constructor(name:string) {
  6. this.name = name;
  7. }
  8. sayHello () {
  9. console.log('sayHello');
  10. }
  11. }
  12. class Dog extends Animal {
  13. // 2. 在子类中使用 构造函数
  14. age: number;
  15. constructor(name:string, age:number) {
  16. // 在最前面 调用父类的 constructor 方法,
  17. // 直接 调用 super() - 必须手动调用
  18. super(name) // 这里就是在调用 父类的构造函数
  19. this.age = age; // 报错
  20. // 因为,继承时,相同的方法会发生重写, 子类写了 constructor 构造函数,相当于重写了 父类的构造函数
  21. // 解决, 在使用子类的 构造函数时, 必须先进行 对父类的构造函数的调用 , 执行 super()
  22. }
  23. // 1.
  24. sayHello () { // 表示重写
  25. // 然后使用 super 关键字
  26. super.sayHello();
  27. // 这里的super 表示当前的父类, 能够拿到父类的的属性|方法
  28. // super , 一般用在 子类 继承 父类时, 需要使用 父类的 方法 或 属性时, 进行调用
  29. // 例如 调用 查看父类的 name
  30. // console.log(super.name); // undefined
  31. // console.log(super); // super 后面必须要跟 父类的 某一个属性 或 方法
  32. }
  33. }
  34. const dog = new Dog("旺财", 123);
  35. dog.sayHello()
  36. })()

抽象类

  1. (function () {
  2. /**
  3. * 以 abstract 开头的类是 抽象类
  4. * - 抽象类和其他类区别不大, 只是不能 用来创建兑现实例化
  5. * - 抽象类就是专门用来被继承的类
  6. */
  7. abstract class Animal {
  8. name: string;
  9. constructor(name:string) {
  10. this.name = name;
  11. }
  12. // 定义一个抽象方法,
  13. // 抽象方法使用 abstract 开头, 没有方法体
  14. // 抽象方法只能定义在 抽象类中, 子类必须对抽象方法进行重写
  15. abstract sayHello():void;
  16. // sayHello () {
  17. // console.log(this.name);
  18. // console.log('sayHello');
  19. // }
  20. }
  21. class Dog extends Animal {
  22. //必须要对 sayHello方法进行重写
  23. sayHello() {
  24. console.log(this.name);
  25. }
  26. }
  27. class Cat extends Animal {
  28. sayHello() {
  29. console.log(this.name);
  30. }
  31. }
  32. const dog = new Dog("🐕");
  33. dog.sayHello()
  34. const cat = new Cat("🐱")
  35. cat.sayHello()
  36. // 这里直接 实例化 Animal 这里大的总类,
  37. // const an = new Animal("🐱") // 使用 abstract class Animal 抽象类后 这里不能够 实例化了
  38. // an.sayHello()
  39. // 以上类方法中的 Animal 类, 如果 Animal 是一个 大型的 类, 并且只能拿来继承
  40. // 所以 可以把Animal 变为一个 抽象类
  41. })()

属性的封装

  1. /**
  2. * 属性的封装
  3. */
  4. (function() {
  5. class Person {
  6. // Ts 独有的 对属性的 修饰方式
  7. /**
  8. * 1. public 修饰的属性可以在任意位置 访问 包括子类 (修改) 默认值,
  9. *
  10. * 2. private 私有属性, 私有属性只能在类内部进行访问,(修改)
  11. * - 如果徐需要修改,通过在类中添加方法使得私有属性可以被外部访问
  12. *
  13. * 3. protected 受包含的属性,只能在当前类 和 当前类的子类 能访问,其他情况下不能访问
  14. */
  15. // 默认值 public _name 可以读, 也可以修改
  16. // _name: string;
  17. // _age: number;
  18. private _name: string;
  19. private _age: number;
  20. constructor(name: string, age: number) {
  21. this._name = name;
  22. this._age = age;
  23. }
  24. /**
  25. * getter 方法用来读取属性
  26. * setter 方法用来设置属性
  27. * 这两个方法被称为属性的存储器
  28. *
  29. * 一把JS中对 属性的处理基本上是这样处理
  30. *
  31. // 读取属性值
  32. getName() {
  33. return this._name;
  34. }
  35. // 修改属性值
  36. setName(value: string) {
  37. this._name = value;
  38. }
  39. // age 也一样
  40. getAge () {
  41. return this._age
  42. }
  43. setAge (value: number) {
  44. // 进行判断
  45. if (value >= 0) {
  46. this._age = value
  47. }
  48. }
  49. */
  50. /**
  51. * 在 TS中 提供了 一种更灵活的方式对 类中的属性 监控
  52. *
  53. *
  54. // get 属性名 () {} ->
  55. // 然后实例中 使用 p.属性名 访问, 相当于 调用了TS定义的 get 属性名这个方法
  56. */
  57. // 读取属性方法
  58. get name() {
  59. console.log("get name () 方法被调用了")
  60. return this._name
  61. // 然后在 实例中 使用 p.name 调用 get name () 方法
  62. }
  63. // 修改属性方法
  64. set name (value:string) {
  65. console.log("set name () 方法执行")
  66. this._name = value;
  67. }
  68. // 同理, age也一样
  69. get age() {
  70. return this._age
  71. }
  72. set age(value:number) {
  73. if (value >= 0) {
  74. this._age = value
  75. }
  76. }
  77. }
  78. /**
  79. * 现在属性是在对象中设置,属性可以任意的被修改
  80. * - 属性可以任被修改将会导致对象中的数据 变得 非常不安全
  81. */
  82. const p = new Person("Yellowsea", 123);
  83. console.log(p)
  84. // 添加 private 后 实例对象 就不能通过 .属性名 修改属性值了
  85. // p._name = 'Hidie'
  86. // p._age = 456
  87. // 实例对象通过 类中的 方法 修改属性值
  88. // console.log(p.getName()) // 通过get 方法获取属性值
  89. // p.setName('Hidie') // 通过 set 方法修改 属性值
  90. // console.log(p.getAge())
  91. // // p.setAge(-123) //经过判断, 修改不了
  92. // p.setAge(456)
  93. // console.log(p)
  94. // 实例使用 TS 的 get set 方法访问属性
  95. console.log(p.name); // get name () 方法被调用了 ——> Yellowsea
  96. p.name = 'Hidie'; // set name () 方法执行
  97. // 同理 age
  98. console.log(p.age);
  99. p.age = 456;
  100. console.log(p);
  101. // 2. 这里讲 protected
  102. // protected 受包含的属性,只能在当前类 和 当前类的子类 能访问,其他情况下不能访问
  103. class A {
  104. // num 属性,是一个 protected 限制的
  105. protected num: number;
  106. constructor(num: number) {
  107. this.num = num;
  108. }
  109. }
  110. class B extends A {
  111. // B 继承了A
  112. show() {
  113. // 子类B 能够访问到 A 中的 num
  114. console.log(this.num);
  115. }
  116. }
  117. const b = new B(123);
  118. b.show() // 123
  119. // 3. 属性的封装简洁写法
  120. class C {
  121. // 直接在构造函数中 确定的 属性的类型,不用再写this.xxx = xxx
  122. constructor(public num: number, public age: number) {}
  123. }
  124. const c = new C(123,456);
  125. console.log(c)
  126. })()
  127. /**
  128. * Ts 中提供的 getter setter 方法
  129. * 使用场景:当对某一个属性值 有比较高的 严格需求时
  130. */

接口

  1. (function () {
  2. // 使用接口来描述对象类型
  3. /**
  4. * 接口: 用来定义一个类的结构 , 用来定义一个类中 应该包含哪些 属性 和 方法
  5. * - 同时接口也可以当成类型声明去使用
  6. * - 接口可以重复声明
  7. */
  8. // 1. 接口用于 类型声明, - 使用在对象中, 跟 type Mytype = {} 类似
  9. // 定义接口
  10. interface myObject {
  11. name: string;
  12. age: number;
  13. }
  14. // 接口可以重复声明 , 相当于合并 两个接口
  15. interface myObject {
  16. gender: string;
  17. }
  18. // 使用接口
  19. const obj: myObject = {
  20. name: "yellowsea",
  21. age: 1,
  22. gender: "男"
  23. }
  24. console.log(obj)
  25. /**
  26. * 2. 接口可以在定义类的时候去限制类的结构
  27. * - 接口中的所有属性都不能有实际的值
  28. * - 接口只定义对象的结构,而不考虑实际的值
  29. */
  30. interface myInter {
  31. name: string;
  32. sayHello(): void; // 返回值为 空
  33. // 接口中的所有属性都不能有实际的值
  34. // 接口只定义对象的结构,而不考虑实际的值
  35. // 接口里的 方法 就是 抽象方法
  36. }
  37. // 定义类时, 可以使用类去实现一个接口 , 必须使用 implements 指定的 接口
  38. // 这个类就是 满足接口的要求
  39. class MyClass implements myInter {
  40. name: string;
  41. constructor (name: string) {
  42. this.name = name;
  43. }
  44. sayHello(){
  45. console.log("Hello")
  46. }
  47. }
  48. /**
  49. * 最后讲讲 接口的作用
  50. * - 接口实际就是定义了一个规范, 当类满足了规范,才能在特定的场景使用
  51. * - 实际上是对类的限制
  52. */
  53. })()

泛型

  1. /**
  2. *
  3. * 08 泛型
  4. */
  5. // 问题:
  6. // function fn (a: number):number {
  7. // return a;
  8. // }
  9. /**
  10. * fn 函数,确定了 a 的类型时,它的返回值同样也确定了
  11. *
  12. * 当 a 的类型不确定时, 有应该怎么 保证 a 的类型 和 函数的返回值呢
  13. *
  14. * - 使用 any , 但是使用了 any, 在 TS 中就相当于关闭了 变量的类型检查。
  15. *
  16. * - 使用泛型。 当函数中的类型不确定时, 使用泛型
  17. */
  18. // 使用泛型
  19. function fn<T>(a: T):T { // 这里的 T 就是泛型,
  20. return a;
  21. }
  22. // 调用
  23. let result = fn(10) // 泛型 T, 自动检查 参数 10 ,然后确定 T 的类型 -> number
  24. // 使用了 TS 中的 自动判断类型
  25. let result2 = fn<string>('hello') // 手动指定 泛型 T 的类型为 string
  26. // 泛型的好处, 就是确定了 参数类型 的明确
  27. // 在调用时, 不用担心类型的不明确
  28. // 2. 泛型可以指定 多个
  29. function fn2<K, T>(a: T, b: K):T {
  30. console.log(b)
  31. return a
  32. }
  33. // 使用时,最好加上类型, 这样更好的避免出错
  34. fn2<string, number>(123,'Hello')
  35. // 3. 指定接口的泛型
  36. interface Inter {
  37. length: number
  38. }
  39. // T extends Inter 定义的泛型 T 指定 Inter 接口
  40. // T extends Inter 泛型T 必须实现 Inter 这个类
  41. function fn3<T extends Inter>(a: T):number {
  42. return a.length
  43. }
  44. fn3('Hello') // str 中有 length 属性
  45. // fn3(123) // error ,
  46. // fn3({name:'yellowsea'}) // error
  47. fn3({length: 2}) // 指定length的属性
  48. // 4. 在类中使用 泛型 T
  49. class MyClass<T> {
  50. // 类中使用 泛型 T
  51. name:T;
  52. constructor(name:T) {
  53. this.name = name;
  54. }
  55. }
  56. const myc = new MyClass(123)
  57. const myc1 = new MyClass('123')
  58. /**
  59. * 总结:
  60. *
  61. * 泛型就是 在变量不明确时,使用一个变量,用这个变量来表示 泛型
  62. *
  63. */