【ts学习笔记】typeScript快速上手的秘籍

编译ts文件

tsc xxx.ts

自动编译

1.生成配置文件tsconfig.json: tsc --init
2.修改tsconfig.json配置:
				“outFirst”:''./js"
				"strict":false
3.启动配置任务:
				终端 --> 运行任务 --> 监视tsconfig.json

webpack打包ts

1.安装相关插件:

   "clean-webpack-plugin": "^3.0.0",
    "cross-env": "^7.0.2",
    "html-webpack-plugin": "^4.5.0",
    "ts-loader": "^8.0.11",
    "typescript": "^4.0.5",
    "webpack": "^4.41.5",
    "webpack-cli": "^3.3.10",
    "webpack-dev-server": "^3.10.2"

2.生成配置文件 (package.json tsconfig.json)

npm init -y
tsc init

3.修改配置文件 package.json

"scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.js",
    "build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
  },

4.新增 webpack.config.js(基本配置)

const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

const isProd = process.env.NODE_ENV === 'production' // 是否生产环境

function resolve(dir) {
  return path.resolve(__dirname, '..', dir)
}

module.exports = {
  mode: isProd ? 'production' : 'development',
  entry: {
    app: './src/main.ts',
  },
  output: {
    path: resolve('dist'),
    filename: '[name].[contenthash:8].js',
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        include: [resolve('src')],
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin({}),
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
  resolve: {
    extensions: ['.ts', '.tsx', '.js'],
  },
  devtool: isProd ? 'cheap-module-source-map' : 'cheap-module-eval-source-map',
  devServer: {
    host: 'localhost',
    stats: 'errors-only',
    port: 8081,
    open: true,
  },
}

5.运行/打包

npm run dev
npm run build

ts的基础类型

1.布尔型 Boolean

let isT:boolean=true
let isF:boolean=false

2.数字型 Number

let decLiteral: number = 6; //十进制
let hexLiteral: number = 0xf00d; //十六进制
let binaryLiteral: number = 0b1010;//二进制
let octalLiteral: number = 0o744;//八进制

3.字符串 String

let name:srting='eiton'
let sentence: string = `Hello, my name is ${ name }.`;
//模版字符串可以定义多行文本和内嵌表达式。 这种字符串是被反引号包围( `),并且以${ expr }这种形式嵌入表达式.

4.null 和 undefined (为其他类型的子类型)

// 两个空类型
let isUndefined: undefined = undefined
let isNull: null = null
// 常见区别
Number(null)  // 0;
Number(undefined) // NaN
console.log(undefined == null) // ture

5.数组

// 某元素组成的数组  元素类型+[]
let numArr:number[] = [1,2,3]

// 数组泛型	Array<元素类型>
let numArr2:Array = [1,2,3]

6.元组 Tuple
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。

let arr: [string, number];
arr = ['hello', 10]; // OK
// arr = [10, 'hello']; // Error

7.枚举类型 Enum
枚举类型里的每个值都可称之为元素,每个元素均有编号(默认:从0开始,依次递增+1)

enum Color {Red=10, Green=20, Blue=30}
let green: Color = Color.Green; // 20
// 可以由枚举的值得到它的名字。 例如,我们知道数值为2,但是不确定它映射到Color里的哪个名字,我们可以查找相应的名字:
let colorName: string = Color[10];

8. Any类型
用于 在编程阶段还不清楚类型的变量指定一个类型
在ts中,any类型的变量跳过类型检查直接通过编译阶段的检查
但尽可能不要用到

let notSure: any = 4;// OK
notSure = "maybe a string instead";// OK
notSure = false;// OK

9.viod类型

// 表示函数没有返回值
function showMsg():void{
	console.log('~~')
}
// 定义void变量,可接收undefined的值,但意义不大
let test:void = undefined
console.log(test) 

10.object类型

function getObj(obj:object):object{
	console.log(obj)
	return {
		name:'eiton',
		age:18
	}
}
console.log(getObj({str:'123'}))
console.log(getObj(new String('123')))

11.联合类型 Union Types
表示取值可以为多种类型中的一种

function getString(str:number|string):string{
	return str.toString()
}

12.类型断言
语法1:<类型>值
语法2: 值 as 类型

function getString(str:number|string):number{
	if((str).length){
		return (str as String).length
	}else{
	return str.toString().length
	}
}

13.类型推断
ts在没有明确指出类型时推断类型
情况1:定义时赋值,推断为对应的类型
情况2:定义时未赋值,推断为any类型

接口

接口是对象的状态(属性)和行为(方法)的抽象(描述)
接口是一种类型,一种规范,一种规则,是一种能力,只一种约束

只读:readonly 属性:类型
非必须: 属性?:类型

 // 需求:创建人的对象,需要对人的属性进行一定的约束
  //	id --- number类型 --- 必须 --- 只读
  //	name --- string类型 --- 必须
  //	age --- number类型 --- 必须
  //	sex --- string类型 --- 非必须

  //	定义Iperson接口,用于限定或约束该对象中的属性数据
  interface Iperson {
    readonly id: number,
    name: string,
    age: number,
    sex?: string
  }
  const person: Iperson = {
    id: 1,
    name: 'eiron',
    age: 18,
    sex: '女'
  }
  const person2: Iperson = {
    id: 2,
    name: 'hhy',
    age: 18
  }

  console.log(person, person2)

函数类型

为了使用接口表示函数类型,我们需要给接口定义一个调用签名。
它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。

  interface Ifunct {
    // 定义一个调用签名
    (source: string, subString: string): boolean
  }
  const searchStr:Ifunct = function (source: string, subString: string): boolean {
    // 查询
    return source.search(subString) > -1
  }

  // 调用函数
  console.log(searchStr('我有个摆烂的同事', '摆烂'))

类类型

类 类型:类的类型,类的类型可以通过接口实现

总结1:
类可以通过接口的方式,来定义当前这个类的类型
类可以实现一个接口,类也可以实现多个接口,要注意,接口中的内容都要真正的实现

总结2:
接口与接口之间叫继承(使用的是extends关键字),类和接口之间叫实现(使用的是 implements 关键字)

  // 定义一个接口
  interface Ifly {
    // 改方法没有任何的实现(方法中什么也没有)
    fly()
  }
  // 定义一个类 ,类的类型是上面定义的接口(可理解为 Ifly接口约束了当前的Person类)
  class Person implements Ifly {
    // 实现接口中的方法
    fly() {
      console.log('我会飞了~')
    }

  }
  // 实例化对象
  const person = new Person()
  person.fly()
  
   // 定义一个接口
  interface ISwim {
    // 改方法没有任何的实现(方法中什么也没有)
    swim()
  }
    // 定义一个类 ,类的类型是上面定义的接口(可理解为 Ifly接口约束了当前的Person类)
  class Person2 implements Ifly, ISwim {
    // 实现接口中的方法
    fly() {
      console.log('我会飞了~')
    }
    swim() {
      console.log('我会游泳了~')
    }
  }
    // 实例化对象
    const person2 = new Person2()
    person2.fly()
    person2.swim()

// 接口可以继承其他的多个接口
  interface IFlyAndSwim extends Ifly, ISwim {
  }
  class Person3 implements IFlyAndSwim {
    // 实现接口中的方法
    fly() {
      console.log('我会飞了~')
    }
    swim() {
      console.log('我会游泳了~')
    }
  }
  const person3 = new Person3()
  person3.fly()
  person3.swim()

可以理解为模板,通过模板可以实例化对象
是面向对象的编程思想

 // ts中类的定义及使用
  class Person {
    // 定义属性
    name: string
    age: number
    gender: string
    // 定义构造函数:为了将来实例化对象的时候,可以直接对属性值进行初始化
    constructor(name: string = "eiton", age: number = 18, gender: string = '女') {
      this.name = name
      this.age = age
      this.gender = gender
    }
    // 定义实例方法
    sayHi(str: string) {
      console.log(`hello everybody~!我是${this.name},今年${this.age},是个${this.gender}孩子`, str)
    }
  }

  // ts中使用类,实例化对象,可以直接进行初始化操作
  const person = new Person()
  person.sayHi('很高兴认识你们~!');
  const person2 = new Person('噸噸坚', 25, '男')
  person2.sayHi('很高兴认识你们~!');

继承

继承:类与类之间的一种关系
举例:a类继承了b类,那么,a类为子类(派生类),b类为基类(超类/父类)

总结:

  1. 继承关键字 — extends
  2. 子类中可以调用父类中的构造函数,使用的是super关键字(调用父类方法也可以用super
  3. 子类中可以重写父类的方法
(()->{
 // 定义一个类作为基类(父类/超类)
  class Person {
    name: string
    age: number
    gender: string
    // 定义构建函数
    constructor(name: string = 'eiton', age: number = 18, gender: string = '女') {
      this.name = name
      this.age = age
      this.gender = gender
    }
    // 定义实例方法
    sayHi(str: string): void {
      console.log(`我是${this.name},今年${this.age},${str}`)
    }
  }
  // 定义一个类,继承自Person
  class Student extends Person {
    constructor(name: string, age: number, gender: string) {
      // 调用父类中的构造函数,使用的是super
      super(name, age, gender)
    }
    // 调用父类中的方法
    sayHi() {
      console.log('Student类中的sayHi方法')
      super.sayHi('很高兴认识你~!')

    }
  }

  // 实例化 Person
  const person = new Person('peach', 22, '女')
  person.sayHi('啦啦啦~');
  // 实例化 Student
  const student = new Student('胖噸噸', 26, '男')
  student.sayHi();
})()

多态

多态:父类型的引用指向了子类型的对象,不同类型的对象针对相同的方法,产生了不同的行为。

// 定义一个父类
  class Animal {
    name: string
    constructor(name: string) {
      this.name = name
    }
    callEvent(sound: string = '嗷呜呜') {
      console.log(`我是一只${this.name},${sound}`)
    }
  }
  // 定义一个子类
  class Dog extends Animal {
    constructor(name: string) {
      // 调用父类的构造函数,实现子类中属性的初始化操作
      super(name)
    }
    // 实例方式,重写父类中的实例方法
    callEvent(sound: string = '汪汪') {
      console.log(`我是一只${this.name},${sound}`)
    }
  }

  // 定义一个子类
  class Cat extends Animal {
    constructor(name: string) {
      // 调用父类的构造函数,实现子类中属性的初始化操作
      super(name)
    }
    // 实例方式,重写父类中的实例方法
    callEvent(sound: string = '喵喵') {
      console.log(`我是一只${this.name},${sound}`)
    }
  }

  // 实例化父类对象
  const ani: Animal = new Animal('动物')
  ani.callEvent('嗷呜~')
  // 实例化Dog类对象
  const dog: Dog = new Dog('旺财')
  dog.callEvent()
  // 实例化Cat类对象
  const cat: Cat = new Cat('来福')
  cat.callEvent()

  console.log('----')

  // 父类和子类的关系:父子关系,此时,父类类型可以创建子类的对象
  const dog1: Animal = new Dog('招娣')
  dog1.callEvent()
  const cat1: Animal = new Cat('顺水')
  cat1.callEvent()

  //
  function showSound(ani: Animal) {
    ani.callEvent()
  }
  console.log('----')
  showSound(dog1)
  showSound(cat1)

修饰符

修饰符(类中成员的修饰符):用于描述类中成员(属性构造函数实例方法)的可访问性
类中成员的默认修饰符为public

public:公共的,任何位置均可访问
private:私有的,仅能在类中才可访问,子类也无法访问
protected:受保护的,仅可在类、子类中访问

 class Person {
    // 定义属性
    public name: string
    private age: number
    protected gender: string
    // 定义构造函数:为了将来实例化对象的时候,可以直接对属性值进行初始化
    constructor(name: string = "eiton", age: number = 18, gender: string = '女') {
      this.name = name
      this.age = age
      this.gender = gender
    }
    // 定义实例方法
    public sayHi(str: string) {
      console.log(`hello everybody~!我是${this.name},今年${this.age},是个${this.gender}孩子`, str)
    }
  }

  // ts中使用类,实例化对象,可以直接进行初始化操作
  const person = new Person()
  // 类的外部可以访问类的属性,实例方法
  console.log(person.name)
  // console.log(person.age) //err
   // console.log(person.gender) //err
  person.sayHi('很高兴认识你们~!');

readonly修饰符

readonly:仅读的,不可修改的。
构造函数中,可对仅读的属性成员的数据进行修改
构造函数中的参数可被readonly修饰,修饰后的该类中就有了这个只读属性,该属性可被外部访问,但不能修改。
构造函数中的参数可被public、private、protected修饰,修饰后的该类会自动添加这个属性成员

 class Person {
    // 定义属性
    readonly name: string
  
    // 定义构造函数:为了将来实例化对象的时候,可以直接对属性值进行初始化
    constructor(name: string) {
      this.name = name
       this.name =  ‘哈哈’  // 可以,但意义不大
    }
    // 定义实例方法
    public sayHi(str: string) {
  	 //  this.name = str 	// err   
    }
  }

let person:Person = new Person('小甜甜')
console.log(person.name) //小甜甜
//person.name = '小怪兽'  // err

存取器

通过getters(get)和setters(set),有效的控制对对象成员的访问

 class Employee {
    firstName: string
    lastName: string
    constructor(firstName: string, lastName: string) {
      this.firstName = firstName
      this.lastName = lastName
    }
    // 姓氏和名字的成员属性(外部可以访问,也可以修改)

    // 读取器
    get fullName() {
      return this.firstName + '_' + this.lastName
    }
    // 设置器
    set fullName(str) {
      let nameArr = str.split('_')
      this.firstName = nameArr[0] || ''
      this.lastName = nameArr[1] || ''

    }

  }

  const emp: Employee = new Employee('Chen', 'Eiton')
  console.log(emp.fullName)
  emp.fullName = '黄_噸噸'
  console.log(emp)

静态成员

在类中通过static修饰的属性或方法,称之为静态属性或静态方法。总称为静态成员。(构造函数不能通过static来修饰)
可以通过类名. 来调用静态成员

class Person {
    // 静态属性
    static name1: string = '小甜甜'
    constructor() {
      // 此时 this 指的是实例对象,name1为静态属性,不能通过实例对象直接调用静态属性来使用
      // this.name1 = name

    }
    static sayHi(str: string = 'hello~!') {
      console.log(str)
    }
  }
  const person: Person = new Person()
  // 通过实力对象调用的属性和方法
  // console.log(person.name1) // 属性
  // person.sayHi(); // 方法

  // 通过 类名. 来访问静态属性 (可以读取,可以修改)
  console.log(Person.name1)
  Person.name1 = '啦啦啦~'
  console.log(Person.name1)
  // 通过 类名. 来调用静态方法 
  Person.sayHi(); // 方法

抽象类

抽象类包含抽象方法(抽象方法一般没有任何具体内容实现),也可以包含实例方法,抽象类是不能被实例化的。
抽象类的最终目的(作用)是为子类(派生类)服务

  // 定义一个抽象类
  abstract class Animal {
    // 抽象属性 
    abstract name: string
    // 抽象方法
    abstract eatEvent()
    // 抽象方法不能有具体的实现
    // abstract eatEvent() {
    //   console.log('真好吃~!')
    // } //err

    // 实例方法
    callEvent() {
      console.log('啦啦啦啦~')
    }
  }

  // 抽象类不能被实例化
  // const ani:Animal=new Animal() //err

  // 定义一个子类(派生类)
  class Dog extends Animal {
    name: string = '噸噸'
    eatEvent() {
      console.log('吃狗粮~!')
    }

  }
  // 实例化 Dog 类
  const dog: Dog = new Dog()
  dog.eatEvent()
  // 调用抽象类中的实例方法
  dog.callEvent()

  console.log(dog.name)

函数

函数:封装重复率高的代码,在使用时直接调用。

  // 函数声明  命名函数
  function add(x: number, y: number): number { //求和函数
    return x + y
  }

  // 函数表达式  匿名函数
  const add2 = function (x: number, y: number): number {
    return x + y
  }
  
  // 函数的完整写法
  const add: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y
  }
  console.log(add(1, 2))

可选参数和默认参数

// 可选参数:函数声明时,内部参数由 ? 修饰的参数(即可传可不传)。
 // 默认参数:函数声明时,内部参数存在默认值的参数。
  const fullName: (firstName: string, lastName?: string) => string = function (firstName: string, lastName?: string): string {
    if (lastName) {
      return firstName + '_' + lastName
    } else {
      return firstName
    }
  }
  console.log(fullName('Chan', 'Eiton'))
  console.log(fullName('Chan'))

剩余参数(rest参数)

  // 剩余参数
  // ...args:string[]表示:剩余的参数放在了字符串数组中
  function showMsg(str: string, ...args: string[]) {
    console.log(str) // aa
    console.log(args) //["bb", "cc"]
  }
  showMsg('aa', 'bb', 'cc')

函数重载
函数重载:函数名相同,函数参数及个数不同。

 // 函数重载声明
  function plus(x: string, y: string): string
  function plus(x: number, y: number): number

  // 函数声明
  function plus(x: string | number, y: string | number): string | number {
    if (typeof x === 'string' && typeof y === 'string') {
      return x + y
    } else if (typeof x === 'number' && typeof y === 'number') {
      return x + y
    }
    return '啥也不是'
  }

  console.log(plus('a', 'b'))
  console.log(plus(1, 2))
  // console.log(plus('a', 2)) //err  添加 函数重载声明后,遇见非法参数"报红"

泛型

在定义函数、接口、类时,不能预先确定要使用的数据的类型,而是在使用时才能确定的类型

泛型参数

单个泛型参数
function getArr(value: T, count: number): T[] {
    // const arr:T[]=[]
    const arr: Array = []
    for (let i: number = 0; i < count; i++) {
      arr.push(value)
    }
    return arr
  }
  const arr1 = getArr(100.123, 3)
  console.log(arr1)
  console.log(arr1[0].toFixed(1))
  const arr2 = getArr('aaa', 3)
  console.log(arr2)
  console.log(arr2[0].split(''))

 // 多个泛型参数
  function getMsg(value1: K, value2: V): [K, V] {
    return [value1, value2]
  }
  const msg = getMsg(12, 'aaa')
  console.log(msg)

泛型接口

在定义接口时,为接口中的属性或方法定义泛类类型,在使用接口时,再指定具体的泛型类型。

// 接口中的泛型
  interface IBaseCURD {
    data: Array
    add: (t: T) => T
    getUserId: (id: number) => T
  }

  class User {
    id?: number
    name: string
    age: number
    constructor(name: string, age: number) {
      this.name = name
      this.age = age
    }
  }
  class UserCRUD implements IBaseCURD {
    data: Array = []
    add(user: User): User {
      user.id = Date.now() + Math.random()
      this.data.push(user)
      return user
    }
    getUserId(id: number): any {
      console.log("输出this.data", this.data)
      console.log(this.data.find(user => user.id === id));
      return this.data.find(user => user.id === id)
    }


  }
  const userCRUD: UserCRUD = new UserCRUD()
  userCRUD.add(new User('jeck', 22))


  let { id } = userCRUD.add(new User("eson", 30))
  userCRUD.add(new User("luck", 25))
  userCRUD.add(new User("may", 22))

  console.log(userCRUD.data);
  console.log(id);
  typeof id == 'number' ? console.log("查找成功", userCRUD.getUserId(id)) : console.log("查找失敗");

泛型类

定义一个类,类中的属性值的类型不确定,方法中的参数及返回值的类型也不确定
注:number和Number、string和String 是不一样的

// 泛型类
  class className{
    defaultValue: T

    constructor(defaultValue: T) {
      this.defaultValue = defaultValue
    }
    add: (x: T, y: T) => T
  }
  const obj1: className = new className(100)
  obj1.add = function (x, y) {
    return x + y
  }
  obj1.add(8, 8)

  const obj2: className = new className('aaa')
  obj2.add = function (x, y) {
    return x + y
  }
  obj2.add('sef', '?')

泛型约束

 // 泛型约束
  // 定义一个接口 用于约束
  interface ILen {
    length: number
  }

  function getLen(x: T): number {
    return x.length
  }

  console.log(getLen('hello everybody~'))
  //console.log(getLen(123)) // err:Type 'number' does not satisfy the constraint 'ILen'.

其他

声明文件

// // 1.安装 jq 插件  npm install jquery
// // 2.引入第三方库 jq
// import jQuery from 'jQuery'
// // 3.定义操作
// declare var jQuery: (selector: string) => any  // 一般定义会放在 jQuery.d.ts 文件(自动扫描,不需引入)中
// // 4.使用 jq
// jQuery('选择器')



// // 将 定义会放在 jQuery.d.ts 文件(自动扫描,不需引入)中
// jQuery('选择器')

/* 
  当时用第三方库时,我们需要引入它的声明文件,才能获得对应的代码补全、接口提示等功能;
  声明语句:如果需要ts对新的语法进行检查,需要加载了对应的类型说明代码
   declare var jQuery: (selector: string) => any 
  声明文件:吧声明语句方式单独的文件中( jQuery.d.ts ),ts会自动解析到项目中所有声明文件
  下载声明文件:npm install @types/jquery --save-dev
*/

// 下载声明文件后
import jQuery from 'jQuery'
jQuery('选择器')

内置对象

ECMAScript 的内置对象


  // ECMAScript 的内置对象

  let b: Boolean = new Boolean(1)
  let n: Number = new Number(true)
  let s: String = new String('abc')
  let d: Date = new Date()
  let r: RegExp = /^1/
  let e: Error = new Error('error message')
  b = true
  // let bb: boolean = new Boolean(2)  // error

BOM 和 DOM 的内置对象

  // BOM 和 DOM 的内置对象

  const div: HTMLElement = document.getElementById('test')
  const divs: NodeList = document.querySelectorAll('div')
  document.addEventListener('click', (event: MouseEvent) => {
    console.dir(event.target)
  })
  const fragment: DocumentFragment = document.createDocumentFragment()

你可能感兴趣的:(前端基础,学习)