TypeScript学习笔记

目录

简介

一:环境搭建

二:基本类型

三:Ts配置与编译

四:webpack - ts

五:webpack - babel

六:面向对象 - 类

七:构造函数- constructor

八:继承 - extends & super

九:抽象类 - abstract

十:接口 - interface

十一:类属性的访问权限

十二:范型


简介

        以JavaScript为基础构建的语言,一个JavaScript的超集。扩展了JavaScript并添加了类型

        可以在任何支持JavaScript的平台执行,不能直接被JavaScript解析器直接执行(需要进行编译)

一:环境搭建

1: 下载并安装Node.js:下载 | Node.js 中文网

2: npm全局安装typescript
        命令行输入:npm i -g typescript

3: 验证typescript安装成功(部分截图)

        命令行输入:tsc


4: 创建一个ts文件

5: 使用tsc命令对ts文件进行编译
        进入命令行  =>  进入ts文件所在目录  => 执行命令:tsc xxx.ts

二:基本类型

通过类型声明可以指定TS中变量(参数、形参)的类型,指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错

let 变量: 类型;

let 变量: 类型 = 值;

//最后一个是指定返回值类型
function fn(参数: 类型, 参数: 类型): 类型{
    ...
}

常见类型

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


1:number

//a 的类型设置为了number,在以后的使用过程中a的值只能是数字
let a: number = 6;
//a = 'hello'; // 此行代码会报错

2:string

let b: string;
b = 'hello';
// b = 123; // 此行代码会报错

3:boolean

let c: boolean = false;

// 如果变量的声明和赋值是同时进行的,TS可以自动对变量进行类型检测
let c = false;
c = true;

4:字面量

//通过字面量可以确定变量的取值范围
//可以使用 | 来连接多个类型(联合类型)
let color: 'red' | 'blue' | 'black';
let num: 1 | 2 | 3 | 4 | 5;

5:any

//any 表示的是任意类型,一个变量设置类型为any后相当于对该变量关闭了TS的类型检测
// 使用TS时,不建议使用any类型
let d: any = 4;(显式的any)
d = 'hello';
d = true;

// 声明变量如果不指定类型,则TS解析器会自动判断变量的类型为any 
let d;(隐式的any)

6:unknown

// unknown 表示未知类型的值
let e: unknown;
e = 10;
e = "hello";
e = true;


// unknown 实际上就是一个类型安全的any,不能直接赋值给其他变量
//s = e; //报错
if(typeof e === "string"){
    s = e;
}

7:void

// void 用来表示空,以函数为例,就表示:没有返回值的函数
function fn(): void{
}

8:never

// never 表示永远不会返回结果
function fn2(): never{
    throw new Error('报错了!');
}

9:object

// object表示一个js对象
let a: object;
a = {};
a = function () {
};


// 语法:{属性名:属性值,属性名:属性值}
// 在属性名后边加上?,表示属性是可选的
let b: {name: string, age?: number};
b = {name: '石昊', age: 18};

// [propName: string]: any 表示任意类型的属性。必须包含name属性,其余的可有可无
let c: {name: string, [propName: string]: any};
c = {name: '火灵儿', age: 18, gender: '女'};

/*
*   设置函数结构的类型声明:
*       语法:(形参:类型, 形参:类型 ...) => 返回值
* */
let d: (a: number ,b: number)=>number;
//等价于 《 === 》 
// d = function (n1: string, n2: string): number{
//     return 10;
// }

10:array

/*
*   数组的类型声明:
*       类型[]
*       Array<类型>
* */
// string[] 表示字符串数组
let e: string[];
e = ['a', 'b', 'c'];

// number[] 表示数值数值
let f: number[];

let g: Array<number>;
g = [1, 2, 3];


11:tuple

/*
*   tuple元组,元组就是固定长度的数组
*       语法:[类型, 类型, 类型]
* */
let h: [string, number];
h = ['hello', 123];

12:enum

/*
* enum 枚举
*
* */
enum Gender{
    Male,
    Female
}

let i: {name: string, gender: Gender};
i = {
    name: '石昊',
    gender: Gender.Male // 'male'
}

13:类型断言 & 类型别名

//可以用来告诉解析器变量的实际类型
/*
* 语法:
*   1:变量 as 类型
*   2:<类型>变量
*
* */

let e: unknown;
let s: string;

s = e as string;
s = <string>e;



// 类型的别名
type myType = 1 | 2 | 3 | 4 | 5;
let k: myType;
k = 2;

三:Ts配置与编译

(一):自动编译文件

使用 -w 指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。

        命令行: tac xxx.ts(编译)

                        tsc xxx.ts -w(编译并监视)

(二):自动编译整个项目

        第一步:在项目根目录下创建一个ts的配置文件 tsconfig.json

        第二步:在tsconfig.json文件中,添加配置项

配置选项如下:

1:include - 希望被编译文件所在的目录

        默认值:["\*\*/\*"]

        例如:"include":["src/**/*", "tests/**/*"] <所有src目录和tests目录下的文件都会被编译>

2:exclude - 需要排除在外的目录

        默认值:["node_modules", "bower_components", "jspm_packages"]

         例如:"exclude": ["./src/hello/**/*"] <src下hello目录下的文件都不会被编译>

3:extends - 被继承的配置文件

        例如: "extends": "./configs/base" <当前配置文件中会自动包含config目录下base.json中的所有配置信息>

4:files - 指定被编译文件的列表,只有需要编译的文件少时才会用到

        例如: "files": [
              "core.ts",
              "sys.ts",

                ...
            ]
<列表中的文件都会被TS编译器所编译>

5:compilerOptions - 包含多个子选项,用来完成对编译的配置

{
  "extends": "@tsconfig/node20/tsconfig.json",//自动包含tsconfig.json中的所有配置信息
  "include": ["vite.config.*"],//所有src目录和tests目录下的文件都会被编译
  "exclude": ["/node_modules"],//node_modules目录下的文件不会被编译
  "files": ["core.ts","sys.ts"], //列表中的文件都会被TS编译器所编译

  "compilerOptions": {
    "target": "ES6", //所编写的ts代码将会被编译为ES6版本的js代码
    "lib": ["ES6", "DOM"],
    "module": "CommonJS",
    "outDir": "dist", //设置后编译后的js文件将会生成到dist目录
    "outFile": "dist/a.js", // 所有js文件合并为一个a.js文件
    "rootDir": "./src", //指定src为根目录
    "allowJs": true, //对js文件进行编译
    "checkJs": true,    //对js文件进行检查
    "removeComments": true,    //删除注释
    "noEmit": true,    //不对代码进行编译
    "sourceMap": true,    //生成sourceMap
  }
}

        (1):target - 设置ts代码编译的目标版本

                可选值:ES3(默认)、ES5、ES6/ES2015、ESNext等

        (2):lib - 指定代码运行时所包含的库(宿主环境)

                可选值:ES3(默认)、ES5、ES6/ES2015、ESNext、DOM、WebWorker、ScriptHost等

        (3):module - 编译后代码使用的模块化系统

                可选值:CommonJS、UMD、AMD、System、ES2020、ESNext、None

        (4):outDir - 编译后文件的所在目录

                默认情况下,编译后的js文件会和ts文件位于相同的目录,设置outDir后可以改变编译后文件的位置

        (5):outFile - 将所有的文件编译为一个js文件

                默认会将所有的编写在全局作用域中的代码合并为一个js文件,如果module制定了None、System或AMD则会将模块一起合并到文件之中

        (6):rootDir - 指定代码的根目录

                默认情况下编译后文件的目录结构会以最长的公共目录为根目录,通过rootDir可以手动指定根目录

        (7):allowJs - 是否对js文件编译

        (8):checkJs - 是否对js文件进行检查

        (9):removeComments - 是否删除注释

                默认值:false

        (10):noEmit - 不对代码进行编译

                默认值:false

        (11):sourceMap - 是否生成sourceMap

                默认值:false

6:严格检查  

        strict: 启用所有的严格检查,默认值为true,设置后相当于开启了所有的严格检查

        alwaysStrict: 总是以严格模式对代码进行编译

        noImplicitAny: 禁止隐式的any类型

        noImplicitThis: 禁止类型不明确的this

        strictBindCallApply: 严格检查bind、call和apply的参数列表

        strictFunctionTypes: 严格检查函数的类型

        strictNullChecks: 严格的空值检查

        strictPropertyInitialization: 严格检查属性是否初始化

7:额外检查      

        noFallthroughCasesInSwitch: 检查switch语句包含正确的break

        noImplicitReturns: 检查函数没有隐式的返回值

        noUnusedLocals: 检查未使用的局部变量

        noUnusedParameters: 检查未使用的参数

8:高级

        allowUnreachableCode: 检查不可达代码

        可选值:

                true - 忽略不可达代码

                false - 不可达代码将引起错误

        noEmitOnError: 有错误的情况下不进行编译

        默认值 - false

四:webpack - ts

TS同样结合构建工具Webpack一起使用

1: 初始化项目

        进入项目根目录,执行命令  npm init -y , 创建package.json文件。


 2: 下载构建工具, 共安装7个包

npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin clean-webpack-plugin

webpack: 构建工具webpack

webpack-cli: webpack的命令行工具

webpack-dev-server: webpack的开发服务器

typescript: ts编译器

ts-loader: ts加载器,用于在webpack中编译ts文件

html-webpack-plugin: webpack中html插件,用来自动创建html文件

clean-webpack-plugin: webpack中的清除插件,每次构建都会先清除目录

3: 根目录下创建webpack的配置文件webpack.config.js

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

module.exports = {
    optimization:{
        minimize: false // 关闭代码压缩,可选
    },

    entry: "./src/index.ts",
    
    devtool: "inline-source-map",
    
    devServer: {
        contentBase: './dist'
    },

    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "bundle.js",
        environment: {
            arrowFunction: false // 关闭webpack的箭头函数,可选
        }
    },

    resolve: {
        extensions: [".ts", ".js"]
    },
    
    module: {
        rules: [
            {
                test: /\.ts$/,
                use: {
                  loader: "ts-loader"     
                },
                exclude: /node_modules/
            }
        ]
    },

    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title:'TS测试'
        }),
    ]

}

4: 根目录下创建tsconfig.json,配置可以根据自己需要

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

5: 修改package.json添加如下配置

{

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack",
        "start": "webpack serve --open chrome.exe"
    },

}

6:在src下创建ts文件,并在并命令行执行 npm run build 对代码进行编译,或者执行 npm start 来启动开发服务器

五:webpack - babel

结合babel来对代码进行转换以使其可以兼容到更多的浏览器

1: 安装依赖包:

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

共安装了4个包, 分别是:

@babel/core: babel的核心工具

@babel/preset-env: babel的预定义环境

@babel-loader: babel在webpack中的加载器

core-js: 用来使老版本的浏览器支持新版ES语法

2: 修改webpack.config.js配置文件

...
module: {
  rules: [
    {
      test: /\.ts$/,
      use: [
        {
          loader: "babel-loader",
          options:{
            presets: [
              [
                "@babel/preset-env",
                {
                    "targets":{
                        "chrome": "58",
                        "ie": "11"
                    },
                    "corejs":"3",
                    "useBuiltIns": "usage"
                }
              ]
            ]
          }
        },
        {
            loader: "ts-loader",

        }
      ],
      exclude: /node_modules/
    }
  ]
}
...

如此一来,ts编译后的文件会再次被babel处理,使得代码可以在大部分浏览器中直接使用,可以在配置选项的targets中指定要兼容的浏览器版本。

六:面向对象 - 类

在程序中一切皆是对象

在程序中所有的对象都被分成了两个部分 - 数据和功能,以人为例:

人的姓名、性别、年龄、身高、体重等属于数据,

人可以说话、走路、吃饭、睡觉这些属于人的功能。

数据在对象中被成为属性,而功能就被称为方法。

使用class关键字来定义类
   对象中主要包含两个部分

  •     属性
  •     方法

直接定义的属性是实例属性,需要通过对象的实例去访问
    let person = new Person();
    person.name
使用static关键字开头的是静态属性(类属性),可以直接通过类访问
    Person.age 

readonly 表示只读属性不能修改

直接定义的方法是实例方法,需要通过对象的实例去访问
    person.upLevel();
使用static关键字开头的是静态方法(类方法),可以直接通过类访问
    Person.upLevel();

<script setup lang="ts" name="theTsClass">
class Person{
  //实例属性
  name:string = '石昊';

  //静态属性 在属性前使用static关键字可以定义类属性
  //readonly 只读属性不能修改
  static readonly age:number = 18;

  // 定义方法
  static upLevel(){
    console.log('升级神火境');
  }
}

let person = new Person();
//实例属性 通过实例来访问
console.log('person.name=',person.name);
//静态属性 通过类来访问
console.log('Person.name=',Person.age);

//静态方法 通过类来访问
Person.upLevel();
</script>

七:构造函数- constructor

constructor 就是构造函数
调用时机:在对象创建的时候调用,即new的时候调用

<script setup lang="ts" name="theConstroctor">

class Person{
  // 一:定义属性
  name: string;
  age: number;

  constructor(name:string, age:number){
    // 实例方法中,this指代当前的实例(新建的那个对象)
    // 可以通过this向新建的对象中添加属性
    // 二:属性赋值
    this.name = name;
    this.age = age;
  }

  upLevel(){
    // 可以通过this来代表当前调用方法的对象
    console.log(this);
  }
}

let person = new Person('石昊',18);
let person1 = new Person('火灵儿',18);

person.upLevel();
person1.upLevel();
</script>

八:继承 - extends & super

extends  -  继承

继承父类的所有属性和方法 (Person父类|超类 ---- codePeople子类)

方法重写 : 重新写父类中的方法(会覆盖),为子类单独所有

super  -  调用父类的构造函数

子类中如果写了构造函数,则必须在子类的构造函数中对父类进行调用

需要传参:父类中的属性名,数量及名称保持完全一致

子类的构造函数会 覆盖 父类的构造函数

class Person{
  name: string;
  age: number;

  constructor(name:string, age:number){
    this.name = name;
    this.age = age;
  }
  upLevel(){
    console.log('提升技能');
  }
}
/* extends 
  继承父类的所有属性和方法 (Person父类|超类 - codePeople子类)
  方法重写 : 重新写父类中的方法(会覆盖),为子类单独所有 */
class codePeople extends Person{
  hobby: string
  
  /* 在子类中写了构造函数,则必须在子类的构造函数中对父类进行调用
  子类的构造函数 会覆盖父类的构造函数 */
  constructor(name: string, age: number, hobby:string){
    //调用父类的构造函数
    super(name, age); 
    this.hobby = hobby
  }
  upLevel(): void {
    console.log('敲代码呀敲代吗')
  }
}

class testPeople extends Person{
  // upLevel(): void {
  //   console.log('自动化测测测')
  // }
}

let person = new codePeople('码农',18,'弹吉他');
let person1 = new testPeople('测试',18);

console.log('person',person) //{name: '码农', age: 18, hobby: '弹吉他'}
person.upLevel();  //敲代码呀敲代吗
person1.upLevel(); //提升技能

九:抽象类 - abstract

抽象类 - 以关键字 <abstract> 开头

与其他类区别不大,只是不能用来创建对象

专门用来被继承

抽象方法 - 以关键字 <abstract> 开头

没有方法体,只能定义在抽象类中

子类 必须 对抽象方法进行重写

只能定义在抽象类中

//抽象类 - 以关键字-abstract开头
abstract class Person{
  name:string
  

  constructor(name:string){
    this.name = name;
    
  }
  //抽象方法 - 以关键字-abstract开头
  abstract upLevel():void
}
class codePeople extends Person{
  age:number
  constructor(name:string, age:number){
    super(name);
    this.age = age;
  }
   upLevel(): void {
     console.log('敲代码呀敲代码')
   }
}

let person = new codePeople('章三',18);
console.log('person==',person);

十:接口 - interface

interface:接口用来定义一个类的结构,包含哪些属性和方法

          也可以当做类型去使用

          可以同时定义多个相同的interface,属性和方法会进行加和

                接口中所有的属性和方法 都不能有具体的值

                方法都是抽象方法

                只定义结构,不考虑值

implements: 实现接口,定义类时,可以去实现接口

        实现接口:让类满足接口的要求 - 所有的属性和方法

/* 接口
用来定义一个类的结构,包含哪些属性和方法
接口也可以当做类型去使用
可以同时定义多个相同的interface,属性和方法会进行加和 
接口中所有的属性和方法 都不能有具体的值
  方法都是抽象方法
  只定义结构,不考虑值
*/
interface myInterface {
  name: string;
  age: number;
  singsong(): void;
}

/* 定义类时,可以去实现一个接口
  实现接口:让类满足接口的要求 - 所有的属性和方法 */
class myInter implements myInterface {
  name: string;
  age: number;
  constructor(name: string, age: number){
    this.name = name;
    this.age = age;
  }
  singsong(){
    console.log('唱歌')
  }
}

let inter = new myInter('石昊',12);
console.log('inter===',inter) //myInter{name: '石昊', age: 12}

十一:类属性的访问权限

1: public:(默认值) 共有属性, 可以在任意位置访问/修改

2: private: 私有属性, 只能在当前类内部访问/修改

        通过在类中添加方法, 让私有属性可以在外部被访问

        确保数据的安全

3: protected:受保护的属性,只能在当前类、子类中访问/修改

属性可以借助getter / setter方法来访问 ,他们被称为属性读取器 

        getter 方法用来读取属性
        setter 方法用来修改属性

class Person {
  private name: string;
  private age: number;
  constructor(name: string, age: number){
    this.name = name;
    this.age = age;
  }
  getName(){
    return this.name;
  }
  setName(val:string){
    this.name = val;
  }
}

let person = new Person('石昊', 18)
person.getName(); //石昊
person.setName('火灵儿') //火灵儿
console.log('person=',person)

声明类的简易写法

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

// <!-- 写法 等价于  -->

class Person {
  //可以直接将属性定义在构造函数中
  constructor(public name: string, public age: number){
  }
}

十二:范型

范型:在类型不明确的时候,使用变量来表示类型

           FName...范型的名称,可以定义任意类型的名称

           不指定范型,TS会自动对类型进行推断

            指定范型:使用尖括号<>

//FName 范型的名称,可以定义任意类型的名称
//类型一
function fn<FName>(a:FName):FName{
  console.log('a==',a)
  return a;
}
// 可以直接调用使用范型的函数
fn(123); // 不指定范型,TS会自动对类型进行推断
fn<string>('456'); //指定范型
fn<boolean>(true);
//类型二
function fn2<FName,FName2>(a:FName, b:FName2):FName{
  console.log('a=',a,'----b=',b);
  return a;
}
fn2<string, number>('123',456);
//类型三
interface inter{
  length: number
}
//FanName extends inter 必须是inter实现类/子类
function fn3<FanName extends inter>(a:FanName):number{
  console.log('a.length=',a.length)
  return a.length;
}
fn3('kfjsdka')
//类型四
class MyClass<Fan>{
  name:Fan;
  constructor(name:Fan){
    this.name = name;
  }
}
let sh = new MyClass<String>('石昊')
console.log('sh==',sh)

  • 23
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值