TS学习笔记

  • TS学习笔记已关闭评论
  • 176 次浏览
  • A+
所属分类:Web前端
摘要

区别:接口,只能为对象指定类型类型别名,不仅可以给对象指定类型,实际上可以为任意类型指定别名


类型

类型 例子 描述
number 1,2,-2 任意数字
string 'hi',"hi" 任意字符串
boolean true,false 布尔值或者true false
字面量 其本身 限制变量的值就是该字面量的值
any * 任意类型
unknown * 类型安全的any
void 空值(undefined) 没有值或者undefined
never 没有值 不能是任意值
array [1,1,2] 任意js数组
object {name:"孙悟空"} 任意js对象
tuple [4,5] 元素,TS新类型,固定长度的数组
enum enum{A,B} 枚举,TS新类型

接口interface与类型别名type

区别:

接口,只能为对象指定类型

类型别名,不仅可以给对象指定类型,实际上可以为任意类型指定别名

//接口 interface  IPerson = {   name: string   age: number   sayHi(): void }  // 类型别名 type IPerson = {   name: string   age: number   sayHi(): void }  let person: IPerson = {   name: '刘老师',   age: 18,   sayHi() {} }  //类型别名   type NumStr = number | string 	 let numStr: NumStr = 33 let numStr2: NumStr = '66' 

字面量类型

思考以下代码,两个变量的类型分别是什么?

let str1 ='Hello Ts' const str2 : 'Hello Ts' 

通过 TS 类型推论机制,可以得到答案:

1. 变量 str1 的类型为:string。

2. 变量 str2 的类型为:'Hello TS'。

解释:

1. str1 是一个变量(let),它的值可以是任意字符串,所以类型为:string。

2. str2 是一个常量(const),它的值不能变化只能是 'Hello TS',所以,它的类型为:'Hello TS'。

注意:此处的 'Hello TS',就是一个字面量类型。也就是说某个特定的字符串也可以作为 TS 中的类型。

除字符串外,任意的 JS 字面量(比如,对象、数字等)都可以作为类型使用。

let str1 = 'Hello TS'  const str2: 'Hello TS' = 'Hello TS'  let age: 18 = 18 

使用模式:字面量类型配合联合类型一起使用。
使用场景:用来表示一组明确的可选值列表。
比如,在贪吃蛇游戏中,游戏的方向的可选值只能是上、下、左、右中的任意一个。
解释:参数 direction 的值只能是 up/down/left/right 中的任意一个。
优势:相比于 string 类型,使用字面量类型更加精确、严谨

 function changeDirection(direction: 'up' | 'down' | 'left' | 'right') {}  changeDirection('left') 

枚举类型

//枚举 /**  *enum  */ enum Gender {   Male = 0,//可以写=0  也可以不写   Female = 1, }  let i1: { name: string; gender: Gender }; i1 = {   name: "孙悟空",   gender: Gender.Male, }; console.log(i1.gender === Gender.Female); 
// 枚举:  enum Direction {   Up,   Down,   Left,   Right }  function changeDirection(direction: Direction) {}  changeDirection(Direction.Left)  

枚举的功能类似于字面量类型+联合类型组合的功能,也可以表示一组明确的可选值。

枚举:定义一组命名常量。它描述一个值,该值可以是这些命名常量中的一个。

解释:

1. 使用 enum 关键字定义枚举。

2. 约定枚举名称、枚举中的值以大写字母开头。

3. 枚举中的多个值之间通过 ,(逗号)分隔。

4. 定义好枚举后,直接使用枚举名称作为类型注解。

可以直接使用 . 来访问枚举中的成员

数字枚举 字符串枚举

TS学习笔记

TS学习笔记

枚举是 TS 为数不多的非 JavaScript 类型级扩展(不仅仅是类型)的特性之一。

因为:其他类型仅仅被当做类型,而枚举不仅用作类型,还提供值 (枚举成员都是有值的)。

也就是说,其他的类型会在编译为 JS 代码时自动移除。但是,枚举类型会被编译为 JS 代码

enum Direction {   Up = 'UP',   Down = 'DOWN',   Left = 'LEFT',   Right = 'RIGHT' } 

​ ⬇

var Direction; (function (Direction) {     Direction["Up"] = "UP";     Direction["Down"] = "DOWN";     Direction["Left"] = "LEFT";     Direction["Right"] = "RIGHT"; })(Direction || (Direction = {})); 

说明:枚举与前面讲到的字面量类型+联合类型组合的功能类似,都用来表示一组明确的可选值列表。

一般情况下,推荐使用字面量类型+联合类型组合的方式,因为相比枚举,这种方式更加直观、简洁、高效。

any类型

原则上不推荐使用any类型这会让 TypeScript 变为 “AnyScript”(失去 TS 类型保护的优势)。

因为当值的类型为 any 时,可以对该值进行任意操作,并且不会有代码提示

let obj: any = { x: 0 }  // 访问不存在的属性 或者 赋值 // obj.aaa // obj.aaa = 10  // 当作函数调用 // obj()  // 赋值给其他类型的变量 // let n: number = obj  // --  // let a // a = 1 // a = '' // a()  // function add(num1, num2) {} // add(1, 2) // add(1, '2') // add(1, false) 

解释:以上操作都不会有任何类型错误提示,即使可能存在错误!

尽可能的避免使用 any 类型,除非临时使用 any 来“避免”书写很长、很复杂的类型!

其他隐式具有 any 类型的情况:1 声明变量不提供类型也不提供默认值 2 函数参数不加类型。

注意:因为不推荐使用 any,所以,这两种情况下都应该提供类型!

unknown与any

unknown只霍霍自己 赋值给别人是不行的 而any只要跟他沾边都会被霍霍都变成any

unknown就是个类型安全的any 赋值给别人前必须做判断

let e: unknown = 'str'; let s: string; //unknown 赋值给别人需要先判断类型 if (typeof e === "string") {   s = e; } //或者类型断言 s = e as string; s = <string>e;   

联合类型

let a = "male" | "female" a = "male"; a = "female"; 

typeof

TS学习笔记

void never

主要用于函数返回值的确定

function fn(num): void {   if (num>0) {     return; //不应有返回值   } else {     return undefined;   } } function fn2(): never{   throw new Error("出错了");//就是执行不完 一定会出错 }   

object 与函数结构的类型声明

一般是不用object 限制太宽泛了

let a1: object; a1 = {} a1 = function () {    }; //用于指定哪些属性 let b1: { name: string, age?: number }//加上问好表示属性可选 b1 = { name: '孙悟空' } let c1: { name: string, [propName: string]: any }// [propName: string]: any表示可以有任意类型的属性 c1 = { name: "猪八戒", age: 18, gender: "male" } //定义函数的参数结构 的类型声明 let d1: (a: number, b: number) => number; d1 = function (a: number, b: number) { return a + b; };  

array

//数组 let e1: string[];//表示字符串数组 e = ['a', 'b', 'c', 'd']; let f1: number[]; let g1: Array<number>; 

元组

长度固定的数组

//元组 /**  * 语法: [类型,类型,类型]  */ let h1: [string, string, number]; h1 = ["hello", "world", 123]; 

或 | 和 与&

 // |  表示或   & 表示且  let j1: { name: string } & { age: number } j1={name: "孙悟空",age:18} 

编译选项

tsc app.ts -w

-w watch模式 只监视app.ts

使用tsc 编译此项目下的全部ts文件 前提是得由tsconfig.json文件 即使这个文件为空json也会按照默认的选项来编译!

webpack打包TS

package.json 需要哪些包

{   "name": "ts-webpack",   "version": "1.0.0",   "description": "",   "main": "index.js",   "scripts": {     "test": "echo "Error: no test specified" && exit 1",     "build": "webpack",     "start": "webpack  serve --open  "   },   "author": "",   "license": "ISC",   "devDependencies": {     "@babel/core": "^7.18.13",     "@babel/preset-env": "^7.18.10",     "babel-loader": "^8.2.5",     "clean-webpack-plugin": "^4.0.0",     "core-js": "^3.24.1",     "html-webpack-plugin": "^5.5.0",     "ts-loader": "^9.3.1",     "typescript": "^4.7.4",     "webpack": "^5.74.0",     "webpack-cli": "^4.10.0",     "webpack-dev-server": "^4.10.0"   } }  

webpack.config.js 定义打包的方式

//引入路径包 const path = require("path"); //引入一个插件包 const HTMLWebpackPlugin = require("html-webpack-plugin");  //引入clean插件 const { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.exports = {   //添加模式   mode: "development",   //指定入口文件   entry: "./src/index.ts",   //指定打包文件所在目录   output: {     //指定目录     path: path.resolve(__dirname, "dist"),     //指定名字     filename: "index.js",     //配置环境兼容问题     environment: {       arrowFunction:false     }   },   //指定打包时要用到的模块   module: {     rules: [       {         //test指定的是规则生效的文件         test: /.ts$/, //匹配以ts结尾的文件         //use 要使用的loader  数组中的内容从后往前执行         use: [           {             //设置加载器             loader: "babel-loader",             //设置babel             options: {               //设置预定义的环境               presets: [                 [                   //指定环境的插件                   "@babel/preset-env",                   //配置信息                   {                     //要兼容的默认浏览器                     targets: {                       //浏览器版本                       "chrome": "58",                       "ie":"11"                     },                     //指定corejs的版本                     "corejs": "3",                     //使用corejs的方式                     "useBuiltIns": "usage"                   }                 ]               ]              },           },           "ts-loader",         ],         //exclude 排除哪些文件         exclude: /node-modules/,       },     ],   },   //配置webpack的插件   plugins: [     new CleanWebpackPlugin(),     new HTMLWebpackPlugin({       // title: "这是一个自定义的title",       template: "./src/index.html",     }),   ],   //用来设置引用模块   resolve: {     extensions: [".ts", ".js"],   }, };  

tsconfig.json ts的编译方式

{   "compilerOptions": {     "module": "ES2015",     "target": "ES2015",     "strict": true   } } 

//使用class关键字来定义一个类 /**  *   属性    *   方法  */ class Person{   //实例属性   name: string = "孙悟空";   //在属性前加关键字static可以定义类属性(静态属性)即不需要创建实例就可访问的属性   static age: number = 18;   //只读属性   readonly gender: string = "male";    //实例方法   say() {     console.log('hello')   }   //静态方法   static run() {     console.log('run')   }  } const per = new Person(); console.log('per.name', per.name); console.log('per', per); per.say();   console.log('Person.age', Person.age) Person.run(); 

构造函数与this

class Dog{   name: string;   age: number;   //构造函数   constructor(name: string, age: number) {     console.log('构造函数执行了',this)     this.name= name     this.age= age   }    bark() {     console.log('wangwangwang')   } } const dog = new Dog('xiaohei',4); console.log('dog',dog) 

类的继承

(() => {   class Animal {     name: string;     age: number;     constructor(name: string, age: number) {       this.name = name;       this.age = age;     }     sayHello() {       console.log(`${this.name}sayHello`);     }   }    class Dog extends Animal {     sayHello(): void {       console.log("wangwangwang"); //子类覆盖掉父类的方法的形式叫重写     }   }    class Cat extends Animal {     run() {       console.log(`${this.name}run`);     }   }   const dog = new Dog("旺财", 5);   const cat = new Cat("咪咪", 3);   console.log("cat", cat);   console.log("dog", dog);   dog.sayHello();   cat.sayHello();   cat.run(); })();  

super

(() => {   class Animal {     name: string;      constructor(name: string) {       this.name = name;        }     sayHello() {       console.log(`${this.name}sayHello`);     }   }    class Dog extends Animal {     age: number;     constructor(name: string, age: number) {        super(name);//必须先调用父类的构造函数       age = this.age;     }      sayHello(): void {       super.sayHello(); //super表示当前类的父类     }   }    const dog = new Dog('旺财',1);   dog.sayHello(); })();  

抽象类

(() => {   abstract class Animal {     //我们不希望直接用Animal来创建实例,我们只需要让它是一个超类 用来被继承     //所以我们给它加上abstract   那么这个类就只能被继承    不能用它创建实例     //抽象类可以添加抽象方法     name: string;      constructor(name: string) {       this.name = name;     }     //抽象方法只能在抽象类里定义  抽象方法没有方法体     //子类必须对抽象方法进行重写     abstract sayHello(): void;   }    class Dog extends Animal {     //非抽象类继承抽象类 必须重写父类中的抽象方法     sayHello(): void {       console.log("汪汪汪");     }   }    const dog = new Dog("旺财");   dog.sayHello(); })();  

接口

(() => {   /**    * 对于类型声明(类型别名) 只能声明一次    *    * 对于接口 可以重复声明  多次声明那么创建的实例应把接口中的定义的都实现    *           接口可以限制类的结构    *           接口只定义类的结构不定义类的实际值    *           接口的所有方法都是抽象方法    *    *    *    */   //描述一个对象的类型   类型别名   type myType = {     name: string;     age: number;   };   let obj: myType = {     name: "sss",     age: 1,   };    /**    * 接口用来定义一个对象的结构    * 用来定义一个类中应该包含哪些属性和方法    */   interface myInterface {     name: string;     age: number;   }   interface myInterface {     gender: string;     sayHello(): void;   }    let obj1: myInterface = {//当作类型使用     name: "aaa",     age: 2,     gender: "male",     sayHello() {       console.log("hello");     },   };    //实现接口   class Myclass implements myInterface {      name = '孙悟空';     age = 18;     gender = 'male';     sayHello() {        console.log("嘿嘿")     }   } })();  

属性的封装

private getter setter

(() => {   class Person {     name: string;     age: number;     constructor(name: string, age: number) {       this.name = name;       this.age = age;     }   }    let per = new Person("孙悟空", 18);   console.log("per", per);   per.name = "猪八戒";   per.age = -18;   console.log("per", per); //可以任意修改 年龄能有负数嘛?   /**    * 上面的属性是在对象中设置的,属性可以任意的被修改    *  属性可以任意被修改将会导致对象中的数据会变得非常不安全    */   class Animal {     /**q      * 可以在属性前添加修饰符      */     public name: string; //公共属性可以在任意位置(访问)更改  默认就是public     private age: number; //私有属性 只能在类内部(访问)修改     constructor(name: string, age: number) {       this.name = name;       this.age = age;     }     //getter 添加方法让私有属性可以在外部访问     getAge() {       return this.age;     }     //setter 设置属性     setAge(value: number) {       if (value > 0) {         this.age = value;       }     }   }   let dog = new Animal("旺财", 2);   console.log("dog", dog);   console.log("dog.getAge()", dog.getAge());   dog.setAge(-8);   console.log("dog", dog); //改不了 })();  

protected 与 constructor 语法糖

(() => {   class Person {     name: string;     age: number;     constructor(name: string, age: number) {       this.name = name;       this.age = age;     }   }    let per = new Person("孙悟空", 18);   console.log("per", per);   per.name = "猪八戒";   per.age = -18;   console.log("per", per); //可以任意修改 年龄能有负数嘛?   /**    * 上面的属性是在对象中设置的,属性可以任意的被修改    *  属性可以任意被修改将会导致对象中的数据会变得非常不安全    */   class Animal {     /**q      * 可以在属性前添加修饰符      */     public _name: string; //公共属性可以在任意位置 包括子类 (访问)更改  默认就是public     private _age: number; //私有属性 只能在类内部(访问)修改     //protected   受保护的属性,只能在当前类和当前类的子类中访问     constructor(name: string, age: number) {       this._name = name;       this._age = age;     }     // //getter 添加方法让私有属性可以在外部访问     // getAge() {     //   return this.age;     // }     // //setter 设置属性     // setAge(value: number) {     //   if (value > 0) {     //     this.age = value;     //   }     // }      //ts中设置获取属性 设置属性 的方法  不会改变访问数据的方法     /**      * 不是特别复杂的修改时  一般用不到      */     get age() {       return this._age;     }     set age(value: number) {       if (value > 0) {         this._age = value;       }     }   }   let dog = new Animal("旺财", 2);   // console.log("dog", dog);   // console.log("dog.getAge()", dog.getAge());   // dog.setAge(-8);   console.log("dog.age", dog.age);   // console.log("dog", dog); //改不了   dog.age = 8;   console.log("dog", dog);    /**    * 语法糖    */    class C {     //得用public     constructor(public name: string, public age: number) {}   }   let c = new C("666", 6);   console.log("c", c); })();  

泛型

(() => {   function fn(a: any): any {     return a;   }   /**    * 在定义函数或是类时遇到类型不明确的  可以使用泛型    *    */   function fn1<T>(a: T): T {     //我不知道a到底是是么类型但是我知道 返回值和入参的类型时相同的     return a;   }   fn1(10); //自动推断   fn1<string>("test"); //类型断言    function fn2<T, K>(a: T, b: K): T {     console.log("b", b);     return a;   }   fn2(123, "test");   fn2<number, string>(333, "test");    interface Test {     length: number;   }   //泛型T得是Test的实现类(子类)   function fn3<T extends Test>(a: T): number {     return a.length;   }   fn3([1, 2, 2]); //传入的参数的类型得是Test接口的实现类 })();  

仓库地址:https://gitee.com/bbigger004/tslearn.git