TypeScript学习笔记

1. 了解TS

TypeScript学习笔记_第1张图片

1.1 TS与JS的关系

  1. 超集与子集: TypeScript 是 JavaScript 的超集,这意味着任何有效的 JavaScript 代码也是有效的 TypeScript 代码。你可以直接在 TypeScript 中使用 JavaScript 语法。

  2. 静态类型检查: TypeScript 引入了静态类型系统,允许开发者在编译时捕获错误,而不是在运行时。这有助于提高代码质量、减少 bug,并且在大型项目中尤其有用。

  3. 可选的类型注解和接口: TypeScript 提供了类型注解和接口,使得开发者能够定义变量、函数参数和返回值的具体类型。这些类型信息是可选的,但在需要的地方提供类型注解可以帮助工具(如 IDE)提供更好的代码提示和自动完成。

  4. 新的语言特性: TypeScript 预先实现了许多 ECMAScript 标准草案中的新功能,例如类、模块、装饰器等。开发人员可以在 TypeScript 中使用这些新功能,然后编译成大多数浏览器可以理解的 ES5 或更低版本的 JavaScript 代码。

  5. 编译步骤: TypeScript 需要一个编译步骤来将源代码转换为 JavaScript,这个过程通常由 tsc 编译器或构建工具(如 Webpack 或 Gulp)处理。而 JavaScript 可以直接被浏览器执行,无需编译。

  6. 兼容性: 虽然 TypeScript 是 JavaScript 的超集,但并非所有第三方库都提供了 TypeScript 类型定义文件(.d.ts)。幸运的是,社区已经创建了很多这样的类型定义文件,可以通过 npm 安装并使用。

1.3 环境搭建

由于ts要运行,需要呗解析器转换为js才可以,解析器是基于node.js实现的,故要先安装node.js

1.3.1 下载node.js

官网地址:Download | Node.js

1.3.2 安装node.js

#安装成功后查看版本命令行输入
node -v
#设置国内的淘宝精选
npm config set registry https://registry.npm.taobao.org/

1.3.3 安装ts

#进入命令行输入
npm i -j typescript  安装ts
#查看ts版本命令行输入
tsc -v

1.3.4 创建文件

创建一个以.ts结尾的文件

console.log('hello ts')

1.3.5 编译ts文件

(1)命令行进入当前目录。

(2)执行命令:tsc xxx.ts

(3)该文件夹下会生成一个xxx.js文件,为ts编译后的js文件。浏览器可以直接引入使用。

1.4 数据类型

1.4.1 类型声明

(1)类型的声明:

       (1.1) 类型的声明是ts非常重要的一个特点。

        (1.2)通过类型的声明,可以指定ts中变量(参数,形参)的类型。

        (1.3)指定类型后,变量重新赋值与原声明类型不同就会提示报错。

        (1.4)变量声明类型后,就只能储存某种类型的值

        (1.5)备注:虽然还可以编译为js(js中并没有问题,所以可以编译通过),但是后续

                               可以通过配置使其编译不通过。

语法:

//声明变量a,类型为num
let a:number
let b:string
//如果声明后立刻赋值,ts会自动检测类型
let c=true
/*函数中的参数,
    js并不会指定类型
    ts中不仅会指定类型,还会判定参数数量,也可以指定返回值类型
*/
function sum(a:number,b:number):number{
    return a+b
}

(2)自动判断类型:

        当赋值与声明同时进行,ts会自动判断变量的类型(类型判断机制)。

(3)函数中的参数:

    js并不会指定类型

    ts中不仅会指定类型,还会判定参数数量,也可以指定返回值类型。

1.4.2 ts中的数据类型

1.4.2.1基本数据类型

(1)Boolean(布尔型):表示真或假的值,如 true 或 false

(2)Number(数字型):表示整数或浮点数,如 42 或 3.14。在 TypeScript 中,所有的数值类型都使用浮点数来表示。

(3)String(字符串型):表示文本信息,如 "Hello, world!"

(4)Null 和 Undefined:分别表示 JavaScript 的 null 和 undefined 值。注意,在          TypeScript 中,null 和 undefined 是不同的类型。

(5)Symbol:唯一标识符,可以作为对象属性的键。

 1.4.2.2特殊类型

(1)Any(任意型):表示任何类型的值,通常用于在不清楚类型的情况下提供灵活性

(2)Unknown(未知型):与 any 类似,但具有更强的限制,它不兼容除 null 和 undefined 之外的所有类型,除非明确转换。

(3)Void(空型):表示永远不会返回的函数类型,例如抛出错误或无限循环的函数。

(4)Never(永不型):表示永远不会返回的函数类型,例如抛出错误或无限循环的函数。

(5)字面量:直接声明let a:'10',a只能为'10',可以配合||等运算符使用

 let a3:'10'
 a3='10'
 let b3:'10'|10
 b3='10'
 b3=10

注意:any关闭ts类型检测,如声明了变量,不声明类型,也不赋值(类型判断机制)那么默认就是any。如果将一个以声明类型的变量赋值为一个any类型,那么被声明类型的变量也会被关闭语法检测,Unknown则不会关闭被声明类型的变量的语法检测。

Unknown实际上是一个类型安全的any,要想使用需要先进性类型检测


let test1 = '10'
let any1: any;
test1 = any1
let unKonw1: unknown;
unKonw1 = '10'
if (typeof unKonw1 === "string") {
    test1 = unKonw1;
}

或者使用类型断言

test1=unKonw1 as string
test1=unKonw1

1.4.2.3复合数据类型

(1)Array(数组型):由相同类型的元素组成的数据结构,可以是任意类型的数组,如 number[]string[] 或 [string, number][]。可以使用泛型来定义更灵活的数组类型,例如 Array

定义数组类型声明:

let strarr:string[]
let strarr2=Array

(2)Tuple(元组型):固定长度且元素类型的组合,例如 [string, number] 表示一个包含一个字符串和一个数字的元组。

(3)Object(对象型):一组键值对,可以通过字面量语法创建,也可以通过接口(Interface)或者类(Class)定义。属性名加?表示属性可选,[propName:string]:any,表示任意多个属性名,任意类型。

指定对象包含哪些属性:

let obja :{
    name:string,
    age?:number,
    [propName:string]:any
}

设置函数结构的类型声明:

let fun1 :(a:number,b:number)=>number;
fun1=function(a,b){
    return 10
}

(4)Enum(枚举型):一组命名的常量,可以用数字或字符串来表示。

定义枚举类:

enum Gender{
    man='1',
    waman='0'
}
let persom:{name:string,sex:Gender}

类型的别名:

type type1=1|2|3|4|5
let k :type1
let l:type1

1.5 TS编译

1.5.1 编译命令

(1)编译单个文件:这将把指定的 TypeScript 文件(例如,filename.ts)编译为 JavaScript 文件(默认情况下,输出文件的名称与输入文件相同,但扩展名为 .js)。

tsc filename.ts

(2)编译整个项目:如果你的项目中有一个 tsconfig.json 文件,你可以直接运行 tsc 来编译整个项目,TypeScript 编译器会根据 tsconfig.json 文件中的配置选项来编译源代码。

tsc

(3)监视文件变化并自动编译:若要在源文件发生变化时自动重新编译,请使用 -w 或 --watch 选项,当你修改了任何源文件后,编译器会自动检测到变化并重新编译。

tsc -w

(4)指定输出目录:使用 --outDir 或 -outDir 选项可以指定输出文件的目录,这样,编译后的 JavaScript 文件会被放置在 dist 目录下。

tsc --outDir dist

(5)生成源映射文件:若要生成源映射文件以方便调试,请使用 --sourceMap 或 -sourcemap 选项:

tsc --sourceMap

(6)设置目标 ECMAScript 版本:
使用 --target 或 -t 选项可以设置输出代码的目标 ECMAScript 版本,这样,编译器会生成兼容 ES6 标准的 JavaScript 代码。

tsc --target es6

完整的 tsc 命令行选项可以在 TypeScript 官方文档中找到:TypeScript: Documentation - tsc CLI Options

1.5.2 编译配置

tsconfig.json文件的配置选项:

1.根级别的配置选项
    1.1)compilerOptions:这是最重要的部分,包含了所有与编译相关的选项。
    1.2)include:用于指定哪些文件应该包含

    1.3)exclude:哪些文件排除在编译范围内。(默认值['node_modles','jspm_packages'

                             , 'bower_components'])。
    1.4)files:分别用来直接指定要编译的文件列表。

    1.5)references:跨项目引用的文件列表。

    1.5)extends:表示继承自哪个文件。

2.compilerOptions 中的一些常见选项
    (2.1)target:设置输出代码的目标 ECMAScript 版本,如 "es5"、"es6"(等同于

                             "es2015")、"esnext" 等。
    (2.2)module:设置模块系统,如 "commonjs"、"amd"、"es2015"(等同于 "es6")等。
    (2.3)lib:指定要在编译过程中引入的库文件。
    (2.4)jsx:控制如何处理 .tsx 文件中的 JSX 语法,可以是 "react" 或 "preserve"。
    (2.5)strict:启用所有严格类型检查选项。
    (2.6)esModuleInterop:启用 ES6 模块导入兼容性。
    (2.7)allowSyntheticDefaultImports:允许从没有默认导出的模块中导入默认值。
    (2.8)alwaysStrict:在生成的 JavaScript 文件中插入 'use strict'(开启严格模式)。
    (2.9)noImplicitAny:当变量没有明确指定类型时,报错而不是推断为 any 类型。

    (2.10)noImplicitThis:不允许出现不明确类型的this。

    (2.11)strictNullChecks:严格检查空值。

    (2.12)outDir:指定输出文件的目录。
    (2.13)sourceMap:生成对应的 .map 文件,便于调试。
    (2.14)allowjs: 它允许编译器处理 JavaScript 文件。(默认false)

    (2.15)checkjs: 它允许检查JavaScript 文件。(默认false)

    (2.16)removeComments:移除注释。

    (2.17)noEmit:不生成编译后的文件。

    (2.18)noEmitOnError:如果有TS语法错误就不生成编译后的文件。

TypeScript 编译器选项的官方文档地址是:TypeScript: Documentation - tsc CLI Options

1.6. webpack打包ts

1.6.1 基本配置

(1)生成package.json文件,在管理目录下使用:

npm -init -y

(2)安装 webpack脚手架,ts,以及tsloader:

npm i -D webpack webpack-cli typescript ts-loader

(3)创建webpack.config.js文件,并配置规则:

//引入包
const path = require('path');
//引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
//webpack的配置信息都应该写在module.exports中
module.exports = {
    //入口文件
    entry: './src/index.ts',
	mode : 'development',   // development为开发者环境,production为生产环境变量 ,还有一个为none
    //打包文件所在目录
    output: {
        //打包文件所在目录
        path: path.resolve(__dirname, 'dist'),
        //打包文件名
        filename: 'bundle.js'
    },
    //指定webpack使用到的模块(loader)
    module: {
        //指定加载规则
        rules: [
            { //指定规则生效文件
                test: /\.ts$/,
                //使用的loader
                use: 'ts-loader',
                //排除的文件
                exclude: /node-modules/
            }
        ]
    },

}

(4)配置tsconfig.json文件:

{
    "compilerOptions": {
        "target": "ES6",
        "module": "system",
        "strict": true
    }
} 

(5)pagckage.json添加命令build:

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build":"webpack"
  },

(6)执行:

npm run build

基本配置完成即可打包成功。

1.6.2 自动创建index.html

如果手动创建html文件,每次新增ts,编译后就要手动引入生成的js。但是webpack提供了一个自动生成index.html的插件,可以帮我们自动生成index.html并且可以自动引入生成的js文件。

(1)引入插件:

npm i -D html-webpack-plugin

(2)webpack.config.js添加配置:

//引入包
const path = require('path');
//引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
//webpack的配置信息都应该写在module.exports中
module.exports = {
    //配置插件选项
    plugins:[new HtmlWebpackPlugin({
        title:'自动生成的html',
        template:'./public/index.html'
    }),]

}

(3)配置模板文件:title:标题,template:指定模板。

(4)运行 npm run build 即可根据配置生成index.html文件。

1.6.3 自动打开

在package.json加入如下配置:

  "scripts": {
    "start": "webpack serve --open "
  },

运行即可在默认浏览器打开生成的html文件。

1.6.4 自动清空dist文件夹

(1)下载插件指令:

npm i -D clean-webpack-plugin

(2)webpack.config.json引入:

const {CleanWebpackPlugin}=require('clean-webpack-plugin')
 plugins:[new HtmlWebpackPlugin({
        //title:'自动生成的html',
        template:'./src/index.html'
    }),
    new CleanWebpackPlugin()]

1.6.5 设置ts可以作为模块引入

(1)webpack.config.json添加新的配置项:

module.exports = {
    //设置可以作为模块引入的文件
    resolve:{
        extensions:['.ts','.js']
    }
}

1.6.6 提高兼容性

(1)下载babel插件:

npm i -D @babel/core @babel/preset-env babel-loader core-js

(2)重新配置规则:

                此时通过babel生成的代码即可兼容到指定的浏览器版本。

 module: {
        //指定加载规则
        rules: [
            { //指定规则生效文件
                test: /\.ts$/,
                //使用的loader
                use: [{
                    //指定加载器
                    loader: 'babel-loader',
                    //设置babel
                    options: {
                        //设置预置环境
                        presets: [
                            [
                                //指定环境的插件
                                "@babel/preset-env",
                                //配置信息
                                {
                                    //要兼容的目标浏览器
                                    targets: {
                                        "chrome": 88
                                    },
                                    //指定corejs的版本
                                    "corejs": "3",
                                    //指定corejs的方式:usage按需加载
                                    "useBuiltIns":"usage"
                                }
                            ]
                        ]
                    }
                },
                    'ts-loader'],
                //排除的文件
                exclude: /node-modules/
            }
        ]
    },

(3)但是有些代码,webpack打包生成,并不会走babel去修改代码,所以如果有些浏览器例如:ie11不支持箭头函数,那么应该设置,webpack不用箭头函数:

output: {
        //打包文件所在目录
        path: path.resolve(__dirname, 'dist'),
        //打包文件名
        filename: 'bundle.js',
        //不使用箭头函数
        environment:{
            arrowFunction:false
        }
    },

2 面向对象

2.1 TS与JAVA

2.1.1 相同

TypeScript (TS) 和 Java 虽然属于不同的编程语言,但它们之间也有一些共同点:

1. 面向对象

  • TypeScript 支持类和接口等面向对象的特性,可以实现封装、继承和多态。
  • Java 是一种完全的面向对象编程语言,所有的代码都必须定义在类中。

2. 静态类型检查

  • TypeScript 引入了静态类型系统,允许开发者在编译时捕获错误,而不是在运行时。
  • Java 同样是一种静态类型的编程语言,要求在声明变量和方法时提供类型信息。

3. 强类型

  • TypeScript 和 Java 都是强类型语言。这意味着一旦一个变量被赋予了一个特定的类型,它就不能被赋值为其他类型的值,除非进行了显式的类型转换。

4. 访问修饰符

  • TypeScript 和 Java 都支持访问修饰符,如 publicprivate 和 protected(java还包含default,用于控制类成员的可见性和可访问性。

5. 命名空间和包管理

  • TypeScript 使用模块(即命名空间)来组织代码,避免全局作用域中的命名冲突。
  • Java 使用包(package)来组织代码,并通过 import 语句引入外部类。

6. 工具和框架支持

  • TypeScript 和 Java 都有丰富的开发工具和框架支持,例如 IDEs(如 Visual Studio Code 或 IntelliJ IDEA)、构建工具(如 Gradle 或 Webpack)以及测试框架。

7. 跨平台

  • TypeScript 编译后的 JavaScript 可以在任何支持 JavaScript 的环境中运行,因此具有良好的跨平台性。
  • Java 则使用 JVM(Java Virtual Machine)实现了“一次编写,到处运行”的理念,可以在多种操作系统上运行。

8. 开源社区和生态系统

  • TypeScript 和 Java 都拥有庞大的开源社区,提供了大量的库和插件来扩展语言功能。

        尽管 TypeScript 和 Java 在许多方面有所不同,但在一些基本的编程范式和设计原则上有相似之处,这使得从一种语言过渡到另一种语言时相对容易。

2.1.2 区别

TypeScript (TS) 和 Java之间的区别

1. 目标平台和执行环境

  • TypeScript 是 JavaScript 的超集,主要应用于浏览器端的前端开发。经过编译后,它生成的是 JavaScript 代码,可以在支持 JavaScript 的环境中运行,如浏览器。
  • Java 是一种面向对象的编程语言,常用于服务器端(后端)开发、Android 移动应用开发等。Java 程序需要在 Java 虚拟机 (JVM) 上运行。

2. 静态类型与动态类型

  • TypeScript 引入了静态类型系统,允许开发者在编译时检查类型错误。虽然 TypeScript 允许使用 any 类型来绕过类型检查,但它鼓励开发人员为变量和函数指定明确的类型。
  • Java 也是一种静态类型的编程语言,要求在声明变量和方法时提供类型信息。编译器会检查类型兼容性,并在编译阶段捕获许多类型相关的错误。

3. 语法风格

  • TypeScript 语法借鉴了许多来自 Java 的特性,例如类、接口、访问修饰符等。这使得熟悉 Java 的开发人员能够相对容易地学习 TypeScript。
  • Java 语法更为严格,遵循更传统的面向对象编程原则,比如强制实现抽象方法、严格的继承关系等。

4. 异步编程

  • TypeScript 由于其对 JavaScript 的原生支持,对于异步编程提供了更好的支持。它支持 Promise、async/await 等异步编程模型,这些在 JavaScript 中广泛使用。
  • Java 对于异步编程的支持相对较弱,但可以通过引入第三方库(如 Reactor、RxJava)来增强这一能力。

5. 包管理器和模块系统

  • TypeScript 通常使用 npm(Node.js 包管理器)来管理依赖项,并通过 ES6 模块或 CommonJS 规范来组织代码。
  • Java 使用 Maven 或 Gradle 进行依赖管理,而模块化方面则有 Java Platform Module System (JPMS),但较新且不如 JavaScript 社区中的模块系统成熟。

6. 运行时性能

  • TypeScript 编译后的 JavaScript 代码是在解释性环境中运行的,性能取决于宿主环境(如浏览器),通常被认为比编译型语言慢。
  • Java 在 JVM 上运行,尽管是解释执行,但 JIT(Just-In-Time)编译器可以将热点代码编译为机器码,从而提高运行效率。

        总的来说,TypeScript 更适合前端 Web 开发,具有更好的类型安全性,而 Java 则在企业级应用、服务器端开发和 Android 应用开发中占据主导地位。不过随着技术的发展,两者的界限也在逐渐模糊,例如 Java 可以通过框架(如 Vaadin)进行 Web 开发,而 TypeScript 也可以用于构建服务端应用程序。

2.2 类的简介

(1)属性:
属性是用来描述对象状态的变量。这些变量存储在对象实例内部,并且可以被类的方法访问。属性可以在类的构造函数中初始化,或者直接声明为类的成员。在 TypeScript 中,你可以指定属性的类型,以确保类型安全。

(2)构造函数(Constructor):
构造函数允许你在创建对象实例时初始化其属性。构造函数接收参数,并赋值给当前对象。

(3)方法:

方法是在类中定义的一组操作,用于实现对象的行为。方法通常是类的一个功能块,可以接收参数并返回值。方法允许你对对象的状态进行操作。

(4)this:
在 OOP 中,方法常常使用 this 关键字来引用当前的对象实例。这使得方法能够访问和修改对象的属性。

//类
class Person{
    //属性
     name:string;
     age:number;
     //构造函数
     constructor(name:string,age:number){
        //this当前对象
        this.name=name;
        this.age=age
     }
     sayName(){
        //this当前对象
        console.log(this.name)
     }
}

const per=new Person('张三',18)
console.log(per);

2.3 类的继承

        在 TypeScript 中,类的继承是一种面向对象编程(OOP)特性,它允许一个类(子类或派生类)从另一个类(基类或父类)继承属性和方法。这样,子类就可以复用父类的功能,并根据需要扩展或修改它们。

        重写方法: 子类可以重写(override)父类的方法。这使得子类能够提供自己的实现来覆盖父类的行为。要重写一个方法,你只需要在子类中定义一个具有相同名称和参数列表的方法。

        请注意,TypeScript 不支持多继承,即一个类只能直接从一个父类继承。但是,通过接口,你可以实现多个接口,从而间接达到类似多继承的效果。

(function () {
    class Animal {
        //属性
        name: string;
        age: number;
        //构造函数
        constructor(name: string, age: number) {
            //this当前对象
            this.name = name;
            this.age = age
        }
        sayName() {
            //this当前对象
            console.log(this.name)
        }
    }
    class Cat extends Animal{
        sleep(){
            console.log('Cat,sleep')
        }
    }
    class Dog extends Animal{
        run(){
            console.log('Dog,run')
        }
    }

    const animal=new Animal('动物',100);
    const cat=new Cat('小猫',12)
    const dog=new Dog('小狗',12)
})

2.4 super

当子类与父类有差异,但是子类还想使用父类的某些属性或者方法时:

(1)调用父类构造函数:

        在子类的构造函数中,你可以使用 super() 来调用父类的构造函数。这样做是为了确保父类的实例被正确地初始化。

(2)访问父类的方法和属性:

        在子类的方法中,你可以使用 super.someMethod() 或 super.someProperty 来直接访问父类的成员。

        这对于重写父类方法并需要调用父类原有实现的情况非常有用。

(function () {
    class Animal {
        //属性
        name: string;
        //构造函数
        constructor(name: string) {
            //this当前对象
            this.name = name;
        }
        sayName() {
            //this当前对象
            console.log(this.name)
        }
    }
    class Cat extends Animal{
         age:number;
         constructor(name: string,age: number) {
            
            super(name);
            //this当前对象
            this.age = age;
        }
        sleep(){
            console.log('Cat,sleep')
        }
    }
   

    const cat=new Cat('小猫',12)
})

2.5 抽象类

(1)概念:抽象类是一种特殊的类,它不能被实例化,只能用作其他类的基类。抽象类用于定义一个蓝图,其中包含一些抽象方法和属性,这些方法和属性需要由继承该抽象类的子类来实现或提供具体值。

(2)主要目的:

(2.1)代码复用:
抽象类可以包含公共的方法和属性,这些方法和属性可以被多个子类共享。这样可以减少重复的代码,并提高代码的可维护性。
(2)接口实现的灵活性:
抽象类提供了比接口更灵活的实现方式,因为抽象类可以包含实现细节(例如,部分实现的方法)。这使得继承自抽象类的子类有更多的自由度来选择如何实现特定的功能。
(3)设计复杂系统的蓝图:
在大型项目或复杂的软件系统中,抽象类可以帮助你设计出一个清晰的层次结构和职责划分。它们可以用作基类,规定一系列必须遵循的规则,而具体的实现细节则留给各个子类。
(4)强制子类实现某些方法:
通过使用抽象方法,你可以确保所有继承自抽象类的子类都实现了特定的方法。
这有助于确保整个程序中的逻辑一致性,并避免由于忘记实现某个方法而导致的错误。
(5)支持多态:
抽象类是实现多态的一种手段,因为它们允许你在父类级别定义通用操作,然后由子类根据需要进行特殊化。
(6)抽象类是一种强大的工具,用于创建可扩展、可维护的代码库,特别是在处理具有多种变体的对象时。

(function () {
   abstract class Animal {
        //属性
        name: string;
        //构造函数
        constructor(name: string) {
            //this当前对象
            this.name = name;
        }
        abstract  sayName()
    }
    class Cat extends Animal{
         age:number;
         constructor(name: string,age: number) {
            
            super(name);
            //this当前对象
            this.age = age;
        }
        sleep(){
            console.log('Cat,sleep')
        }
        sayName() {
            //this当前对象
            console.log(this.name)
        }
    }
   

    const cat=new Cat('小猫',12)
})

2.6 接口

        在TypeScript中,接口(Interface)是一个重要的概念,它用于定义对象的结构和类型。接口定义了一组规范或合同,规定了对象必须具有的形状(属性和方法)。通过使用接口,TypeScript 可以确保值具有正确的结构,从而提供更好的类型安全性。

(1)接口的一些关键特性:

        (1.1)定义对象的形状:你可以使用接口来描述一个对象应该包含哪些属性和方法,以及它们的数据类型。当你创建一个对象并尝试将它赋值给接口类型的变量时,TypeScript 编译器会检查该对象是否符合接口的要求。
        (1.2)可选属性和只读属性:在接口中,你可以指定某些属性为可选的,这意味着它们不是必需的。你也可以声明只读属性,这些属性只能在构造函数或初始化阶段设置一次。

interface Person {
  name: string;
  age?: number; // 可选的年龄
  readonly gender: 'male' | 'female'; // 只读的性别
}

(2)函数类型接口:除了描述对象的形状,接口还可以用来表示函数的形状。这意味着你可以指定参数列表、返回类型等。

interface Greet {
  (name: string): void;
}

function sayHello(greeting: Greet) {
  greeting('John');
}

(3)索引签名:使用索引签名,你可以定义一个对象的键可以是字符串或数字,并且有特定类型的值。

interface StringArray {
  [index: number]: string;
}
let myArray: StringArray = ['hello', 'world'];

(4)类实现接口:类可以实现一个或多个接口,这要求类必须实现接口中定义的所有成员。

interface Animal {
  speak(): void;
}

class Dog implements Animal {
  speak() {
    console.log('Woof!');
  }
}

(5)接口继承:类似于类,接口也可以从其他接口继承,合并它们的形状。

interface Shape {
  color: string;
}

interface Square extends Shape {
  sideLength: number;
}

(6)接口与类型别名的区别:接口和类型别名都可以用来定义复杂的类型,但它们之间有一些区别。类型别名更像一个“别名”,而接口允许你在代码中多次引用相同的形状。

(7)接口可以同名,需要满足两个接口全部的要求。

2.7 属性的封装

在TypeScript中,属性的封装是为了限制对类中属性的访问权限。通过使用不同的访问修饰符,你可以控制哪些代码可以读取或修改这些属性。这样可以确保数据的安全性和完整性。

TypeScript 提供了以下几种访问修饰符来封装属性:

(1)public:

默认情况下,如果没有指定访问修饰符,属性将被标记为 public。public 属性可以在任何地方(包括类的内部和外部)被访问和修改。

class Person {
  public name: string;
  public age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

(2)private:

private 属性只能在类的内部访问和修改。它们不能从类的外部直接访问。

class Person {
  private name: string;
  private age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  getDetails() {
    return `${this.name} is ${this.age} years old.`;
  }
}

const person = new Person('Alice', 30);
console.log(person.getDetails()); // 输出 "Alice is 30 years old."
console.log(person.name); // 错误:'name' 是私有的

(3)protected:

protected 属性类似于 private,但它们也可以在子类中访问。这意味着如果你有一个继承层次结构,子类可以访问父类的 protected 属性。

abstract class Animal {
  protected species: string;

  constructor(species: string) {
    this.species = species;
  }
}

class Dog extends Animal {
  breed: string;

  constructor(breed: string, species: string) {
    super(species);
    this.breed = breed;
  }

  bark() {
    console.log(`${this.breed} says Woof! It's a ${this.species}.`);
  }
}

const dog = new Dog('Labrador', 'Canine');
dog.bark(); // 输出 "Labrador says Woof! It's a Canine."

(4)readonly:

使用 readonly 修饰符,你可以创建只读属性,这意味着它们只能在构造函数中设置一次。在之后的代码中,你无法修改只读属性的值。

class Person {
  readonly name: string;
  readonly age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

const person = new Person('Bob', 35);
person.name = 'Alice'; // 错误:'name' 是只读的

通过这些访问修饰符,你可以更好地控制对象的属性,并避免意外的数据修改。这有助于提高代码的健壮性和安全性。

2.8 泛型

基本概念:

(1)类型参数:

在定义泛型的时候,我们使用尖括号 <> 来包含一个或多个类型参数。例如, 是一个类型参数,代表某种未知类型。

(2)约束:

我们可以为类型参数添加约束,限制它可以是哪些类型或者必须实现哪些接口。例如,extends SomeInterface 就是一个约束条件。

(3)泛型函数:

泛型函数可以在调用时指定具体的类型参数。这使得该函数可以适应多种数据类型。

function identity(arg: T): T {
  return arg;
}

在这个例子中,identity 函数接受任何类型的参数,并返回相同类型的值。T 是一个类型参数,用于捕获传入的参数类型。

(4)泛型接口:

类似地,泛型接口也可以在实例化时指定具体类型。

interface Pair {
  first: T;
  second: U;
}

let x: Pair = {first: 'hello', second: 10};

这个例子展示了如何定义一个包含两个不同类型的属性的泛型接口,并在实例化时指定具体类型。

(5)泛型类:

泛型类允许我们在创建类实例时指定类型参数。

class Box {
  contents: T;

  constructor(contents: T) {
    this.contents = contents;
  }
}

let box = new Box('hello');

这里定义了一个泛型类 Box,它的 contents 属性的类型由泛型参数 T 决定。在创建 Box 实例时,我们指定了 T 为 string 类型。

(6)泛型类型别名:

通过 type 关键字,我们可以定义一个泛型类型别名,方便复用和引用。

(7)泛型上下文:

泛型信息可以从一个作用域传递到另一个作用域,使得关联的类型能够共享类型参数。

        这些只是TypeScript泛型的基本概念和使用方式。实际上,泛型的应用非常广泛,可以用来解决很多复杂的类型问题。对于更深入的学习,建议查阅官方文档和相关教程以获取更多详细的信息和实践技巧。

完..

你可能感兴趣的:(typescript,学习,笔记)