TypeScript学习笔记

学习笔记如下:

基础类型


(() => {
  //布尔类型 ----->boolean
  //基础语法
  //let 变量名:数据类型 = 值
  let flag: boolean = true
  console.log(flag)
  // 数字类型 ----->number
  let a1: number = 10 // 十进制
  let a2: number = 0b1010  // 二进制
  let a3: number = 0o12 // 八进制
  let a4: number = 0xa // 十六进制
  console.log(a1);
  console.log(a2);
  console.log(a3);
  console.log(a4);
  // 字符串类型 ----->string
  let name:string = 'tom'
  name = 'jack'
  // name = 12 // error
  let age:number = 12
  const info = `My name is ${name}, I am ${age} years old!`
  console.log(info);
  //undefined 和 null
  let u: undefined = undefined
  let n: null = null
  //数组 
  let list1: number[] = [1, 2, 3]
  let list2: Array<number> = [1, 2, 3]
  //元祖
  let t1: [string, number]
  t1 = ['hello', 10] // OK
  //t1 = [10, 'hello'] // Error
  console.log(t1[0].substring(1)) // OK
  //console.log(t1[1].substring(1)) // Error, 'number' 不存在 'substring' 方法
  //枚举
  //enum 类型是对 JavaScript 标准数据类型的一个补充。 使用枚举类型可以为一组数值赋予友好的名字。
  enum Color {
      Red,
      Green,
      Blue
    }
  // 枚举数值默认从0开始依次递增
  // 根据特定的名称得到对应的枚举数值
  let myColor: Color = Color.Green  // 0
  console.log(myColor, Color.Red, Color.Blue)
  //默认情况下,从 0 开始为元素编号。 你也可以手动的指定成员的数值。 例如,我们将上面的例子改成从 1 开始编号:
 // enum Color {Red = 1, Green, Blue}
  let c: Color = Color.Green
  //enum Color {Red = 1, Green = 2, Blue = 4}
  //let c: Color = Color.Green
  //enum Color {Red = 1, Green, Blue}
  let colorName: string = Color[2]
  console.log(colorName)  // 'Green'
  //any
  let notSure: any = 4
  notSure = 'maybe a string'
  notSure = false // 也可以是个 boolean
  let list: any[] = [1, true, 'free']
  list[1] = 100
  //void 
  //声明一个 void 类型的变量没有什么大用,因为你只能为它赋予 undefined 和 null:
  //某种程度上来说,void 类型像是与 any 类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void
  /* 表示没有任何类型, 一般用来说明函数的返回值不能是undefined和null之外的值 */
  function fn(): void {
    console.log('fn()')
    // return undefined
    // return null
    // return 1 // error
  }  
  //object
  //object 表示非原始类型,也就是除 number,string,boolean之外的类型。
  //使用 object 类型,就可以更好的表示像 Object.create 这样的 API。例如:
  function fn2(obj:object):object {
  console.log('fn2()', obj)
  return {}
  // return undefined
  // return null
  }
  console.log(fn2(new String('abc')))
  // console.log(fn2('abc') // error
  console.log(fn2(String))
  //联合类型
//联合类型(Union Types)表示取值可以为多种类型中的一种
//需求1: 定义一个一个函数得到一个数字或字符串值的字符串形式值
function toString2(x: number | string) : string {
  return x.toString()
}
//需求2: 定义一个一个函数得到一个数字或字符串值的长度
// function getLength(x: number | string) {
  // return x.length // error
//   if (x.length) { // error
//     return x.length
//   } else {
//     return x.toString().length
//   }
// }
  //类型断言
// 通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript 会假设你,程序员,已经进行了必须的检查。
// 类型断言有两种形式。 其一是“尖括号”语法, 另一个为 as 语法
/* 
类型断言(Type Assertion): 可以用来手动指定一个值的类型
语法:
    方式一: <类型>值
    方式二: 值 as 类型  tsx中只能用这种方式
*/
/* 需求: 定义一个函数得到一个字符串或者数值数据的长度 */
function getLength(x: number | string) {
  if ((<string>x).length) {
    return (x as string).length
  } else {
    return x.toString().length
  }
}
console.log(getLength('abcd'), getLength(1234))
  //类型推断
// 类型推断: TS会在没有明确的指定类型的时候推测出一个类型
// 有下面2种情况: 1. 定义变量时赋值了, 推断为对应的类型. 2. 定义变量时没有赋值, 推断为any类型

/* 定义变量时赋值了, 推断为对应的类型 */
let b9 = 123 // number
// b9 = 'abc' // error

/* 定义变量时没有赋值, 推断为any类型 */
let b10  // any类型
b10 = 123
b10 = 'abc'
})()

接口

// console.log('hellow Ts')
//变量类型的注释
// let age: number;
//变量类型转换
// console.log(2-+'2')

//接口
(() => {
  interface Iperson{
    firstName: string,
    lastName:string
  }
  function showFullName(person: Iperson) {
    return person.firstName +'_'+person.lastName
  }
  //定义一个对象
  const person = {
    firstName:'东方',
    lastName:'不败'
  }
  // 将对象传入函数
  console.log(showFullName(person))
  
})()

(() => {
  // 定义一个接口
  interface Iperson{
    firstName: string,
    lastName:string
  }

  //定义一个类型
  class Person{
    //定义公共的字段
    firstName: string
    lastName: string
    fullName: string
    //定义一个构造函数
    constructor(firstName: string, lastName: string) {
      this.firstName = firstName
      this.lastName = lastName
      this.fullName = this.firstName + '_' + this.lastName
    }
  }
  //定义函数
  function showFullName(person:Iperson) {
    return person.firstName + '_' + person.lastName
  }

  //实例化对象
  const person = new Person('诸葛', '孔明')
  console.log(showFullName(person))
})()

类的继承

// 继承:类与类之间的关系
// 继承后类与类的叫法:
// a类继承了b类,那么刺水a类叫做子类,b类叫做基类
// 子类——派生类
// 基类——超类(父类)
// 一旦发生了继承关系,就出现了父子类的叫法

(() => {
// 定义一个类
  class Person{
    // 定义属性
    name: string
    age: number
     gender:string
    // 定义构造函数
    constructor(name: string, age: number, gender: string) {
      // 更新属性数据
      // 此时,this.name 为属性name,相当于将构造函数获得的参数,传递给属性的每一个值
      this.name = name
      this.age = age
      this.gender = gender
    }
    // 定义实例化方法
    sayHi(str: string) {
      console.log(`我是:${this.name},${str},我今年${this.age}岁,我是${this.gender}的`);
      
    }
  }
  // 定义一个类,继承Person
  class Student extends Person{
    // 子类的自己的属性
    Grade:string
    constructor(name: string, age: number, gender: string,Grade:string) {
      // 调用的是父类的构造函数,使用的是super关键字
      super(name, age, gender)
      // 更新子类属性的数值,将传入来的参数传给上面的属性,并通过{this.属性名}的方式使用该属性
      this.Grade = Grade
    }
    // 可以调用父类的方法
    sayHi() {
        console.log('我是学生类的中sayhi方法');
        // 调用父类的sayhi方法
      super.sayHi('哈哈')
      console.log(`我今年上${this.Grade}`);
      
    }
  }
  // 实例化Person
  const person1 = new Person('大聪明', 18, '男')
  person1.sayHi('嘻嘻')
  // 实例化Student
  const stu1 = new Student('大明白', 20, '男','五年级')
  stu1.sayHi()
})()

类的多态

// 多态:父类型的引用指向了子类型的对象,不同类型的对象针对相同的方法,产生了不同的行为
(() => {
  // 定义一个父类
  class Animal{
  // 定义一个构造函数
    name:string
    constructor(name: string) {
      // 属性数据更新:将实例化方法中的参数赋值给属性值
       this.name = name
    }
    // 实例化方法
    run(distance: number=11) {
      console.log(`${this.name}跑了${distance}米的距离`);
      
    }
  }
  // 定义一个子类
  class Dog extends Animal {
    // 构造函数
    constructor(name: string) {
      //调用了父类的构造函数,实现子类的属性初始化操作,因此子类不需要创建自己的属性,继承了父类的属性以及数据更新操作
      super(name)
    }
    // 实例化方法
    run(distance: number=10){
      console.log(`${this.name}跑了${distance}米的距离`);
    }
  }
  // 定义一个子类
   class Cat extends Animal {
    // 构造函数
    constructor(name: string) {
      //调用了父类的构造函数,实现子类的属性初始化操作,因此子类不需要创建自己的属性,继承了父类的属性以及数据更新操作
      super(name)
    }
    // 实例化方法
    run(distance: number=5){
      console.log(`${this.name}跑了${distance}米的距离`);
    }
   }
   // 定义一个子类
   class Pig extends Animal {
    // 构造函数
    constructor(name: string) {
      //调用了父类的构造函数,实现子类的属性初始化操作,因此子类不需要创建自己的属性,继承了父类的属性以及数据更新操作
      super(name)
    }
    // 实例化方法
    run(distance: number=100){
      console.log(`${this.name}跑了${distance}米的距离`);
    }
   }
  //  实例化父类对象
  const ani:Animal = new Animal('动物')
  ani.run()
  //  实例化子类对象
  const dog:Dog = new Dog('小黑')
  dog.run()
  const cat:Cat = new Cat('小黄')
  cat.run()
  const pig:Pig = new Pig('小白')
  pig.run()
  // 多态:父类型的引用指向了子类型的对象,不同类型的对象针对相同的方法,产生了不同的行为
  // 父类和子类的关系:父子关系,此时,父类类型创建子类的对象
  const dog1: Animal = new Dog('大黑')
  dog1.run()
  const cat1:Animal = new Cat('大黄')
  cat1.run()
  //  多态的作用:在父类中定义一个方法,在子类中有多个实现,在程序运行的时候,根据不同的对象执行不同的操作,实现运行时的绑定。
  // 此时,函数需要传入的是ani是Animal类型
  function showRun(ani: Animal) {
    ani.run()
  }
  showRun(dog1)
  showRun(cat1)
})()

类属性成员中的修饰符

// 修饰符:描述类的属性成员的可访问性,其中修饰符可在构造函数中修饰并定义属性成员
// public 全局可访问 默认修饰符
// private 父类可访问,子类和外部不可访问
// protectd 父子可以访问,外部不可访问
// readonly 父子外部都可以访问,但只有在父类的构造函数中可以修改
(() => {
  // 定义一个类
  class Person{
    // 属性
    public name: string
    age: number
    gender: string
    private data: string
    protected address: string
    readonly ids:number 
    // 构造函数
    // 定义了一个profection属性成员,用修饰符在构造函数里面定义
    constructor(public profection:string,name: string, age: number, gender: string,data:string,address:string,ids:number) {
      this.name = name
      this.age = age
      this.gender = gender
      this.data = data
      this.address = address
      // 构造函数可以修改readonly的数据
      this.ids = ids
    }
    // 方法
    sayHi() {
      // readonly 修饰后,普通方法不可以更改数据
      //this.ids = 1;
      console.log(`身份id:${this.ids},你好,我叫${this.name},是个${this.gender},今年${this.age}岁了,今年是${this.data},家在${this.address}`);      
    }
  }

  // 定义一个子类
  class Student extends Person{
    // 属性
    // 构造函数
    constructor(profection:string,name: string, age: number, gender: string,data:string,address:string,ids:number) {
      super(profection,name, age, gender, data, address, ids)
            // readonly 修饰后,子类构造函数不可以更改数据
      //this.ids =1
    }
    // 方法
    eat() {
      // readonly 修饰后,普通方法不可以更改数据
      //this.ids = 1;
      // private---------------可以继承,但子类也不能访问 
      // protected---------------可以继承,可以访问
      //      console.log(`你好,我叫${this.name},是个${this.gender},今年${this.age}岁了${this.data},家在${this.address}`);
      console.log(`身份id:${this.ids},你好,我叫${this.name},是个${this.gender},今年${this.age}岁了,家在${this.address}`);
    }
  }
  // 实例化时,不管是否修饰符是什么,必要的参数还是需要传进去
  // 实例化父类
  const per1 = new Person('计算机','小明',20,'男孩','2021','深圳',1)
  per1.sayHi()
  // 实例化子类
  const stu1 = new Student('计算机','小红', 18, '女孩','2022','梅州',2)
  stu1.eat()
  // 全局访问 
  console.log(per1.name);
  // private----------------------外部访问不到
  //console.log(per1.data);
  // readonly 修饰后,外部不可以更改数据
  //console.log(per1.ids=1);
  console.log(per1.ids);
  
  
})()

静态成员

// 静态成员:在类中通过static修饰的属性或者方法,那么就是静态属性以及静态方法,也成为静态成员
// 静态成员在使用的时候通过类名.的语法来调用,而不用通过实例化对象的方法去调用
(() => {
  class Person{
    // 静态属性
    // 类中默认有一个内置的name属性,不能重名
    static name1: string = '葫芦娃'
    // 构造函数不能通过static来进行修饰
    constructor() {
      // 此时this是实例对象,name1是静态属性,不能通过实例对象直接调用静态属性的方式来使用
      // this.name1 = name
      
    }
    // 静态方法
   static sayHi() {
      console.log('hello');
      
    }
  }

  // 实例化对象
  const person: Person = new Person()
  //console.log(person.name1);
  
  //通过实例调用方法
  //person.sayHi()

  // 通过类名.属性名的方式来访问 
  console.log(Person.name1);
  Person.name1 = '变形金刚'
  console.log(Person.name1);
  Person.sayHi();
  
  
})()

抽象类

// @ts-nocheck
// 抽象类的作用:为子类服务
// 抽象类:包含抽象方法(抽象方法一般没有任何具体内容的实现)也可以包含实例方法,抽象类是不能被实例化的,只能在被继承以及在子类实例化以及内部的方法
(() => {
  abstract class Animal{
    // 抽象属性:很少使用抽象属性放在子类去实现
    abstract name:string
    // 抽象方法
    abstract eat()
    // abstract eating() { 
    //   console.log('抽象方法不能有具体的实现');  
    // }
    // 实例方法
    sayHi() {
      console.log('hello');
    }


  }
  // 抽象类不能被实例化
  //const ani = new Animal()
  // 通过子类继承后实例化
  // 定义一个子类
  class Dog extends Animal {
    name:string ='小黄'
    // 重新的实现抽象类中的方法,此时这个方法就是当前Dog类的实例方法
    eat() {
        console.log('吃狗粮');
        
    }
  }
  // 实例化Dog类
  const dog:Dog = new Dog()
  dog.eat()
  // 调用的是抽象类中的实例方法
  dog.sayHi()
  console.log(dog.name);
  

})()

ts函数写法

// 函数:封装了一些重复使用的代码,在需要的时候直接调用即可
(() => {
  // js和ts书写方式
  // // 函数生命,命名函数
  // function add(x, y) {
  //   return x + y
  // }
  // // 函数表达式,匿名函数
  // const add2 = function (x, y) {
  //   return x + y
  // }

  // ts写法
  // 函数生命,命名函数
  // 定义了x和y参数为字符串类型,以及定义了返回值是字符串类型
  function add(x: string, y: string): string {
    return x + y
  }
  console.log(add("20", "20"));
  // 函数表达式,匿名函数
  const add2 = function (x: number, y: number): number {
    return x + y
  }
  console.log(add2(10, 20));


  // 函数的完整写法
  // add3 为变量名,函数add3
  // (x: number, y: number) => number 为当前这个函数的类型
  // function (x: number, y: number): number {return x + y} 相当符合上面的这个函数类型的值
  const add3: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y
  }

  console.log(add3(1, 2));

})()

参数:可选参数,默认参数,动态参数

// 可选参数
// 默认参数
(() => {
  // 定义一个函数:传入姓氏和名字,可以到完整名字
  // 需求:如果不传入参数,默认返回姓氏
  // 需求:只传入姓氏,返回姓氏
  // 需求:传入姓氏和名字,返回完整名字
  const getFullName = function (firstName: string = '李', lastName?: string): string {
    // 判断是否传入了姓氏d
    if (lastName) {
      return firstName + '_' + lastName
    }
    return firstName


  }


  // 函数调用
  console.log(getFullName('赵', '子龙'));
  


})()


// 动态参数:传入的参数可以是任意个

(() => {
  function info(name: string, ...args: string[]) {
    console.log(name, args);

  }


  info('必选参数', '动态传入的参数1', '动态传入的参数2', '动态传入的参数3', '动态传入的参数4')
})()



函数重载

// 函数重载:函数名字相同,函数参数及个数不同
// 作用:
(() => {
  // 需求: 我们有一个add函数,它可以接收2个string类型的参数进行拼接,也可以接收2个number类型的参数进行相加 
  // 函数声明重载
  function add(x: string, y: string): string
  function add(x: number, y: number): number

  function add(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   // 数字相加
    }

  }

  // 函数调用
  console.log(add('祝福', '平安'));
  console.log(add(1, 2));
  // 用户传入非法参数,ts应该提示错误信息,可以使用函数重载
  // console.log(add('1', 22));
})()

泛型:泛型的定义以及使用,一个函数多个泛型参数,泛型接口,泛型类

// 泛型:在定义函数、接口、类的时候不能预先确定 要使用的数据类型,而是使用函数、接口、类的时候才能确定数据的类型
(() => {
  // 需求:定义一个函数,传入两个参数,第一个参数是数据,第二个参数是数量,函数的作用:根据数量,产生对应个数的数据,存放在一个数组中

  // 定义一个函数
  function getArr1(val: number, count: number): number[] {
    // 根据数据和数量产生一个数组
    const arr: number[] = []
    for (let i = 0; i < count; i++) {
      arr.push(val)
    }
    return arr
  }
  //做法1: 传入都是数字类型
  // const arr1 = getArr1(100.131, 3)
  // console.log(arr1);
  // console.log(arr1[0].toFixed(2));


  // 定义一个函数
  function getArr2(val: string, count: number): string[] {
    // 根据数据和数量产生一个数组
    const arr: string[] = []
    for (let i = 0; i < count; i++) {
      arr.push(val)
    }
    return arr
  }
  // 做法2: 传入都是字符串类型
  // const arr2 = getArr2("aaaa", 3)
  // console.log(arr2);

  // 定义一个函数:参数使用泛型
  function getArr3<T>(val: T, count: number): T[] {
    // 根据数据和数量产生一个数组
    const arr: T[] = []
    for (let i = 0; i < count; i++) {
      arr.push(val)
    }
    return arr
  }
  const arr3 = getArr3<string>("aaaa", 3)
  console.log(arr3);
  console.log(arr3[0].split(''));

  const arr4 = getArr3<number>(200, 3)
  console.log(arr4);
  console.log(arr4[0].toFixed(2));
  
  // //做法3: 传入都是任意类型ddd
  // const arr3 = getArr3(111, 3)
  // console.log(arr3);
  // console.log(arr3[0].toFixed(2));

})()

// 多个泛型参数的函数,函数中有多个泛型的参数
(() => {
  function getMsg<K, V>(val1: K, val2: V): [K, V] {
    return [val1, val2]
  }


  const arr1 = getMsg<string, number>('tony', 123456)
  console.log(arr1[0].split(''), arr1[1].toFixed(2));

})()
// 泛型接口:在定义接口时,为接口中的属性或者方法定义泛型类型,在使用接口时,在指定具体的泛型类型
// 需求:定义一个类,用来存储用户的相关信息(id,姓名,年龄)

(() => {
  // 定义一个泛型接口
  interface IbaseCRUD<T> {
    // 动态传入T类型,并定义为T类型的数据data
    data: T[]
    // 动态传入T类型,并定义其add函数的参数类型为T类型, =>返回的值也为T类型
    add: (t: T) => T
    // 动态传入T类型,并定义getUserId函数参数类型为number类型,=>返回值为T类型
    getById: (id: number) => void
  }
  // 定义一个用户信息类
  class User {
    id?: number  // 用户ID  ?代表可有可无
    name: string // 用户姓名
    age: number  // 用户年龄
    constructor(name: string, age: number) {
      this.name = name
      this.age = age
    }
  }
  // 使用泛型接口
  // 定义一个类,可以针对用户的信息对象进行增加及查询的操作
  // CRUD ====>create remove undata delete
  class UserCRUD implements IbaseCRUD<User> {
    // 用来保存多个user类型的用户信息对象
    data: User[] = []
    //用来添加存储用户信息对象
    add(user: User): User {
      // 产生id
      user = { ...user, id: Date.now() + Math.random() }
      // 把用户信息对象添加data数组中
      this.data.push(user)
      return user
    }
    // 方法根据id查找指定的用户信息对象
    getById(id: number): void {
      this.data.find(item => item.id === id)
    }
  }

  // 实例化添加用户信息对象的类UserCRUD
  const userCRUD = new UserCRUD()
  const { id } = userCRUD.add(new User('java', 1))
  userCRUD.add(new User('pythone', 2))
  userCRUD.add(new User('php', 3))
  userCRUD.add(new User('javascript', 4))
  console.log(userCRUD.data)
})()


// 泛型类

(() => {
  // 定义一个类,类中属性值的类型不确定,方法中的参数及返回值也不确定
  // 定义一个泛型类
  class GenericNumber<T> {
    zeroValue: T
    add: (x: T, y: T) => T
  }

  let myGenericNumber = new GenericNumber<number>()
  myGenericNumber.zeroValue = 0
  myGenericNumber.add = function (x, y) {
    return x + y
  }

  let myGenericString = new GenericNumber<string>()
  myGenericString.zeroValue = 'abc'
  myGenericString.add = function (x, y) {
    return x + y
  }

  console.log(myGenericString.add(myGenericString.zeroValue, 'test'))
  console.log(myGenericNumber.add(myGenericNumber.zeroValue, 12))
})()
posted @   Chiffon1996  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示