typescrip基础学习

本文详细介绍了 TypeScript 的基础知识,包括环境搭建、类型系统、类型注解与推断、对象与函数结构定义、面向对象特性以及编译选项。通过实例展示了如何使用 TypeScript 进行开发,同时提到了 tsconfig.json 配置文件的使用方法,帮助开发者更好地理解和掌握 TypeScript。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

TypeScript是JavaScript为基础的一门语言,是JavaScript的超集,实际运行时会将其编译成JavaScript。

环境搭建
  • 安装Node.js,并安装
    • 地址:https://nodejs.org/en/
  • 使用npm全局安装typescript
    • 进入cmd界面,输入:npm i typescript -g
  • 创建一个.ts类型文件
  • 编译ts文件
    • 打开命令行界面,进入ts文件所在目录
    • 编译:tsc xxx.ts
      • 执行完这一步后会发现当前目录出现了一个同名的.js文件
类型
  • 类型声明

    • 通过为TS中的变量设置类型,在赋值该变量时需要符合类型声明,否则就会报错。

    • 使用type关键字自定义类型(其实就是为变量重命名)

    • 语法如下:

      // 赋值给变量的值需要符合类型声明
      let 变量: 类型;
      let 变量: 类型 = 值;
      
      // 函数也同样可以设置参数类型、返回值类型
      function fnc(变量: 类型, 变量: 类型) : 返回值类型 {
          // do something
      }
      
      // type关键字
      // 这里个人感觉就是字面量属性换了个名字
      type 自定义类型 =let 变量: 自定义类型 =// 这里的值必须和上面自定义类型的值一致
      // 对象(为对象结构重命名)
      type Person {
      	name: string,
      	age: number,
      	gander: number
      }
      // 这里的obj结构必须和Person一致
      let obj: Person = {
          name: 'Yuiai',
          age: 18,
          gander: 1
      }
      
  • 类型注解和类型推断

    一些简单定义无需类型注解,因为TypeScript会自动推断出其数据类型,如下:

    // 这里的one、two变量会自动推断成number(毕竟已经设置number类型的值了)
    let one = 1
    let two = 2
    // 这里的three的类型也被自动推断为number类型
    // 这里会等于3 而不是报错,因为 one、two其类型已经被推断为number了
    let three = one + two
    
    // 这里的例子与上文其实一致
    function getTolal(num1: number, num2: number) {
        // 这里的返回值 也被自动推断为number类型
        // 所以如果用该函数的返回值作为初始值的变量其类型也被推断为number
        return num1 + num2
    }
    // 这里的total自动被推断为number类型
    let total = getTotal(1, 2) 
    
    // TypeScript会自动推断出对象属性的数据类型(其实跟上文的缘由一致)
    // name: string
    // age: number
    let Yuiai = {
        name: 'Fuyuumiai',
        age: 10
    }
    

    工作使用问题(潜规则)

    • 如果TS能够自动分析变量类型,我们就什么也不需要做了;
    • 如果TS无法分析变量类型的话,我们就需要使用类型注解。
  • 数据类型

    类型取值描述
    number22、-33、3.41数字
    string“hi”、‘hi’、`hi`字符串
    booleantrue、false布尔值
    字面量其本身,如let num: 10;相当于常量
    any任意值任意类型,可赋任意值
    void空值(undefined)表示函数无返回值或(undefined)
    never没有值不能是任何值
    object{name: ‘yuiai’}任意JS引用类型
    array[1, 2, 3]、[‘a’, ‘b’, ‘c’]同一指定类型数据构成的数组
    tuple[1, 2]固定长度数组(类似python的元组)
    enumenum Color {Red, Green, Blue}可以由枚举的值得到它的名字

    实例如下:

    // 使用字面量作为数据类型
    // 这里随后只能将num赋值为10(类似与常量的概念)
    let a: 10;
    a = 10; // true
    a = 11; // false
    
    // 联合类型
    // 可以使用 `|` 分隔多个指定的数据类型,也可以用来分隔多个字面量
    // 这样就可以使用多个数据类型或字面量中的一种
    let b: 1 | 2;
    let c: number | string;
    function fnc(num: number): number | string{
        if (num > 0) {
            return 'ok'
        } else {
            return 0
        }
    }
    
    // any类型的变量在之后可以赋值任何类型的值,相当于普通js的变量
    // 未设置类型的变量的默认类型就是any
    // 但是这样typescript就失去了意义,所以不推荐使用any类型
    let c: any;
    
    // 未知类型(unknown)
    // 有时候变量的类型我们不得而知,所以就可以设置成`unknown`
    let d: unknown;
    
    // void(表示函数的返回值为空)
    // 由于JavaScript函数默认返回undefined,所有return undefined、null是不会报错的
    function sum(): void{}
    
    // never(表示不能有返回值,要区分void)
    // 用来抛出异常,了解即可
    function fn(): never {
        throw new Error('错误信息')
    }
    
    // object (对象类型/引用类型)
    let e: object;
    e = {}; //true
    e = function(){}; //true
    e = new String('hi'); // true
    e = 'hi'; // false
    
    // array(数组类型)
    // 两种设置方式:
    // 类型[]、Array<类型>
    let arr0: string[];
    let arr1: Array<number>;
    arr0 = ['a', 'b', 'c']
    arr1 = [1, 2, 3]
    
    // tuple(元组类型)
    // 用于表示一个已知数量、数据类型的数组,各个元素的数据类型可以不同,如下:
    let tup: [string, number];
    tup = ['a', 1];
    
    // enum(枚举类型)
    // 默认情况下从0开始为元素编号
    enum Color {Red, Green, Blue}
    Color.Red // 0
    // 也可以手动为元素设置值
    // 数字值会自动按序排下去,其他类型的值需要为元素全部设置值
    enum Gender {FaMale = 4, Male}
    Gender.Male // 5
    

    any类型与unknown类型的异同:

    • 相同之处:

      • 可以赋予任意类型的值;
      • unknown其实就是一个类型安全的any
    • 不同之处:

      • any类型的变量可以被赋值给任意类型的变量,即使any类型的变量最后赋的值的类型与当前被赋值变量类型不同;
      • unknown类型的变量不能被直接赋值给其他变量(需进行类型判断或类型断言)
    • 实例:

      let s = string;
      
      // any类型
      let a: any;
      a = 1;
      s = a; // true
      
      // unknown类型
      let b: unknown;
      b = 'hi';
      s = b; // false
      
      // 如果unknown进行了类型判断、类型断言的话就可以赋值
      // 类型判断
      if (typeof b === 'string') {
          s = b; // true
      }
      // 类型断言(相当于断定变量的类型),语法有如下两种
      // 变量 as 类型
      // <类型>变量
      s = b as string; // true
      s = <string> b; // true
      

对象结构定义

  • 创建对象结构

  • 语法

    {属性名:类型,属性名:类型}

    • 实例:

      let a = {
          name: string,
          age: number
      }
      a = {name: 'yuiai', age: 18} //true
      a = {name: 'yuiai'} // false,缺少age属性
      
      // 使用`?`表示对象属性可选
      let b = {
          name: string,
          age?: number
      }
      b = {name: 'yuiai', age: 18} // true
      b = {name: 'yuiai'} // true,因为age属性是可选的
      
      // 使用 `[属性名:string]:类型`,表示对象不固定属性值,类似ES6的rest参数
      // 如下实例,这样就表示name属性为必填,其他属性个数不定
      let c = {
          name: string,
          // 这样表示属性名的类型为string,属性值的类型为任意类型
          [propName: string]: any
      }
      c = {name: 'yuiai'} //true
      c = {name: 'yuiai', age: 18, sex: '男'} // true
      

函数结构定义

  • 创建函数结构(非函数)

  • 语法

    (形参:类型,形参:类型...) => 返回值类型

  • 语法:

    // 使用箭头函数的方式定义
    let fnc: (num: number) => string;
    // true
    fnc = (1) => {
        return 'hi'
    }
    // true
    fnc = function(1){
        return 'hi'
    }
    
  • 定义函数

    // 使用Function、function进行定义
    // 定义一个参数为number类型,返回值为string类型的函数
    // Function
    let fnc: Function;
    fnc = function(num: number): string{
        return 'hi'
    }
    // function
    function fnc0(num: number): string{
        return 'hi'
    }
    // 还可以使用联合类型定义复数的返回值类型
    let fnc1 = function(num: number): string | number{
        if (num > 0) {
            return num
        }
        return 'hi'
    }
    // 当然也可以用到上文的箭头函数形式进行定义
    let fnc: () => string = () => 'hi'
    
编译选项

在编写typescript时,如果每次变更都要使用tsc命令进行重新编译,很麻烦。所以我们需要一种会在我们变更ts文件后自动编译的方法。

  • 方法:

    • 使用tsc xxx.ts -w的方式监听某一个ts文件
      • 缺点:只能对一个文件进行监听,如果需要对其他ts文件进行监听,则需要重复上述命令行操作。
    • 使用配置文件tsconfig.json,以下为vscode使用tsconfig.json的操作方法
      • 使用vscode打开我们要操作的文件夹,打开终端,输入tsc -init命令
      • 此时会在文件夹根目录出现一个tsconfig.json文件
        • 如果编译后的js输出目录不保存在根目录,可以打开tsconfig.json找到outDir属性更改成要输出的目录;
      • 在vscode中, mac: Command+ ⬆️ + B ; windows: Ctrl + Shift + B,设置监听,当该文件夹内的任一ts文件变更之后都会进行重新编译。
  • tsconfig.json配置选项

    tsconfig.jsonts编译器的配置文件,ts编译器可以根据它的信息来对代码进行编译。

    • include:用来指定哪些路径下的ts文件需要编译

      • 示例:仅编译srctests目录下的ts文件(需注意,路径是相对于tsconfig.json

        {
          /*
          	** 表示任意目录
          	*  表示任意文件
          */
          "include": ["src/**/*", "tests/**/*"]
        }
        
    • exclued:用来指定不需要编译的文件目录(实际不常用,且具有默认值)

      • 默认值:

        ["node_modules", "bower_components", "jspm_packages"]
        
      • 示例:排除src目录下的no-compile目录

        {
            "exclued": ["src/no-compile/**/*"]
        }
        
    • extends:定义被继承的配置文件(类似于引入外部配置文件)

      • 示例:引入configs目录下的base.json

        {
            "extends": "./configs/base.json"
        }
        
    • files:指定要进行编译的文件列表,很麻烦,实际不常用

      • 示例:

        {
            "files": [
                "app.ts",
                "index.ts"
            ]
        }
        
    • compilerOptions:编译器的选项配置

      • target:用来指定ts被编译为的ES版本

        • 候选值:所有ES版本,目前有:

          ‘es3’, ‘es5’, ‘es6’, ‘es2015’, ‘es2016’, ‘es2017’, ‘es2018’, ‘es2019’, ‘es2020’, ‘esnext’

        • 示例:ts代码将会编译成ES5版本

          {
              "compilerOptions": {
                  "target": "ES5"
              }
          }
          
      • module:指定要使用的模块化的规范

        • 候选值:none和所有模块化规范,目前有:

          ‘none’, ‘commonjs’, ‘amd’, ‘system’, ‘umd’, ‘es6’, ‘es2015’, ‘es2020’, ‘esnext’

        • 示例:ts模块化语句(引入、导出)将编译成ES6的模块化语句

          {
              "compilerOptions": {
                  "module": "ES6"
              }
          }
          
      • lib:指定代码运行时要包含的库(宿主环境),默认包含运行所需库。

        可以设置错误值,然后在控制台查看能设置的默认值。

      • outDir:用来指定编译后文件所在的目录

        • 示例:将编译后的文件保存在dist文件夹内

          {
              "compilerOptions": {
                  "outDir": "dist"
              }
          }
          
      • outFile:用来指定将编译后的全局作用域的代码汇总到一起的文件

        • 注意:如果需编译的文件中存在模块化语句,且module不是amdsystem编译会报错。

        • 示例:将编译后的文件汇总保存在dist文件夹下的app.js

          {
              "compilerOptions": {
                  "outFile": "dist/app.js"
              }
          }
          
      • allowJs:是否对js文件进行编译,默认为false

      • checkJs:是否检查js代码是否符合ts语法规范,默认为false

      • removeComments:是否移除注释,默认为false

      • noEmit:是否不生成编译后的文件,默认为false,既生成编译后的文件

      • noEmitOnError:是否在被编译文件出错后继续生成编译文件,默认为false,既生成。

      • alwaysStrict:编译后的文件是否采用严格模式,默认为false。

      • noImplicitAny:是否不允许隐式的any类型(如:未声明类型、设置初始值的函数参数),默认为false,既允许。

      • noImplicitThis:是否不允许不明确的this,默认是false,既允许。

      • strictNullChecks:是否严格检查空值,默认为false

      • strict:严格模式的总开关,如果设置为true,那么上述严格检查将会启用,如果关闭需单独设置。

面向对象

​ 这段介绍ts中面向对象的语法。面向对象就是将现实事物抽象化,将其属性抽离,将其行为封装成方法。

  • 类(class)

    • 属性(可以通过设置readonly为属性设置仅读)

      • 实例属性:不加static标识的类属性,只能通过实例化对象获取到

      • 静态属性:加static标识的类属性,通过类可以直接获取到

      • 示例:

        class Person {
            // 实例属性
            name: string;
            // 静态属性
           	static stateMent: string = '这是一个测试类';
            // 可读实例属性、静态属性
            readonly age: number = 18;
            static readonly text: string = '测试可读属性。';
            // 构造函数
            constructor(name: string){
        		this.name = name
          	}
        }
        
        // 通过实例化对象获取实例属性
        let per: Person = new Person('yuiai');
        per.name // yuiai
        
        // 通过类获取静态属性
        Person.stateMent // 这是一个测试类
        
        // 无法更改仅读属性的值
        per.age = 20; // false
        Person.text = '更改可读属性'; // false
        
    • 方法(方法不能进行重载,但是如果子类继承父类的方法可以进行重写)

      • 实例方法:与实例属性类似,不加static关键字,需通过实例化对象进行调用

      • 静态方法:与静态属性类似,需加static关键字,通过类进行调用。

      • 示例:

        class Person {
            name: string;
            constructor(name: string){
        		this.name = name
          	}
            // 实例方法
            sayName(): string{
                return `我的名字是${this.name}`
            }
            // 静态方法
            static sayState(): void{
                console.log('这是一个静态方法!')
            }
        }
        
        class Test extends Person {
            // 继承后方法的重写
            sayName():string {
                return `My name is Yuiai`
            }
        }
        
        let per: Person = new Person('yuiai')
        console.log(per.sayName()) // 我的名字是yuiai
        Person.sayState() // 这是一个静态方法!
        
    • 继承(ts的继承的与ES6的继承无太大区别,个人感觉就是添加了类型)

      • super关键字:父类的指针,可以通过其调用父类的方法

      • 示例:

        class Animal {
            name: string
            constructor(name: string){
                this.name = name
            }
            sayName(): void{
                console.log(`我的名字是${this.name}`)
            }
        }
        
        class Dog extends Animal {
            age: number
            // 需要注意的是,如果要重写构造函数,需要使用super()调用父类的构造函数
            constructor(name: string, age: number){
                // 使用super()调用父类构造函数
                super(name)
                this.age = age
            }
            suggest(): void {
               // 使用super.xxx调用父类的方法
               super.sayName()
               console.log(`我的年龄是${this.age}`)
            }
        }
        
    • 抽象类(abstract

      抽象类是将一类具有相同特征的对象的属性与方法抽象、汇总到一起,并专门给这些对象继承的类(生而为爷)叫做抽象类,要点如下:

      • 不能被实例化;

      • 类中的抽象方法一定要实现;

      • 示例:

        // 抽象类
        abstract class Animal{
            race: string
            constructor(race: string){
                this.race = race
            }
            // 抽象方法
            abstract sayRace(): void
        }
        
        // 继承
        class Cat extends Animal{
            // 这里必须要实现这个抽象方法
            sayRace() {
                console.log(`我的种族是${this.race}`)
            }
        }
        
        new Animal('喵喵') // false
        
        new Cat('喵喵').sayRace() // 我的种族是喵喵
        
    • 接口(与java的接口概念类似,其中全是抽象方法或属性声明)

      • 类似于类型声明(但是与type类型声明不同的是,可以重复定义,最终会进行合并)

      • 可以被类实现

      • 示例:

        // 类型声明,可以重复声明
        interface Person {
            name: string;
            age: number
        }
        interface Person {
            gander: number
        }
        // 这里必须实现全部属性
        let yuiai:Person = {
            name: 'Yuiai',
            age: 18,
            gander: 1
        }
        
        // 类的接口
        interface Fnc {
            name: string;
            age: number;
            say: ()=> string
        }
        // 类必须全部初始化属性、实现方法
        class Yuiai implements Fnc {
            name: string
            age: number
            constructor(name: string, age: number){
                this.name = name
                this.age = age
            }
            say(){
                return 'hi'
            }
        }
        
总结

这篇文章是我边看视频,边总结编写的,基本囊括了TypeScrip的基础知识,希望能帮到大家,如果该篇文章中有错误或不足之处,忘指出,谢谢~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值