TypeScript(个人学习笔记)

一、什么是TypeScript

在这里插入图片描述
在这里插入图片描述

TS增加了:类型,支持ES的新特性,增加了ES不具有的新特性,丰富的配置选项,强大的开发工具。
TS开发环境:安装Node环境、npm安装typescript

npm install -g typescript
// 验证
tsc -v 
// 编译
tsc helloworld.ts

二、类型声明

let  a: number; // 声明另一变量a,同时指定其类型为Number
a = 11; // a的类型为number,在以后的使用过程中a的值只能是数字
a = 'hello'; // 报错,变量a的类型为number,不能赋值“string”
let b: number = 10;
let c = false; // 如果变量和赋值是同时进行的,ts可以自动对变量进行类型检测
c = true

// js中函数是不考虑参数的类型和个数的
function sum(a, b) {
    return a + b;
}
console.log(sum(123, 567)); // 690
console.log(sum(123, '567')); // 123567

// ts 
function sum(a: number, b: number): number { // 指定返回值类型
    return a + b 
}
console.log(sum(123, 567)); // 690
console.log(sum(123, '567')); // 报错,变量a的类型为number,不能赋值“string”
 // 也可以直接使用字面量进行类型声明
let a: 10;
a = 10;
// a = 11; // 报错,不能将类型“11”分配给类型“10”

let b : 'male' | "famale"; // 可以用 | 来连接多个类型(联合类型) “或”
b = "famale";
b = "male";
let c : number | string;
c = 22;
c = "hello"

let d: any; // any 表示的是任意类型,相对于对该变量关闭了ts的类型检测(不建议使用)
d : 10;
d : true;

let e; // 声明变量如果不指定类型,ts解析器会自动判断变量的类型为 any(隐式的any)
e = 33;
e = "world";

let f : unknown; // 表示未知类型的值,unknown是一个类型安全的 any,不能直接赋值给其他变量
f = 555;
f = 'hhh';

let g: string;
g = d;// d的类型是any,可以赋值给任意变量

// g = f; // 报错,不能将类型“unknown”分配给类型“string”。
if(typeof f === 'string') {
    g = f;
}

g = f as string // 类型断言:可以用来告诉解析器变量的实际类型
g = <string> f
function fn(): void {  // void用来表示空,一函数为例,表示没有返回值
    // return true // 报错,不能将类型“boolean”分配给类型“void”。
    
    // return undefined 可以返回undefined,不能返回null,null的也是值的一种,typeof null返回值是 “object”
    return 
}

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

object

let a: object; 
a = {};
a = function () {} // js中万物皆对象

// {} 用来指定对象中可以包含哪些属性,{属性名:属性值,属性名:属性值}
let b: {name: string, age?: number}; // 属性名后加一个 ?表示属性是可选的
// b = {}; // 报错 类型 "{}" 中缺少属性 "name",但类型 "{ name: string; }" 中需要该属性
b = {name: '悟空', age: 18}

let i: {name: string} & {age: number}; // &表示同时 “与”
i = {name: '艾斯', age = 22}

// [propName: string]: any 表示任意类型的属性
let c: {name: string, [propName: string]: any};
c = {name: '八戒', a: 111, c: 222}

// 设置函数结构的类型声明:语法(形参:类型,形参:类型……)=> 返回值
let d: (a: number, b:number) => number;
d = function(n1: number, n2: number): number {
    return n1 + n2
}

数组

let e: string[] // 限制数组存储值的类型
e = ['a', 'b', 'c']
let g: Array<number>
g = [1, 2, 3]

元组Tuple:固定长度的数组

let h: [string, number];
h = ['xixi', 123]

枚举enum:用于定义数值集合

enum Gender {
    male = 0,
    female = 1
}
let i: { name: string, gender: Gender }
i = {
    name: '悟空',
    gender: Gender.male
}
console.log(i.gender === Gender.male);  // true

类型的别名

type myType = 1 | 2 | 3 | 6 | 7;
let k: myType;
let l: myType;
k = 3;
// k = 8; // 报错 不能将类型“8”分配给类型“myType”

三、编译选项

tsc index.ts -w // 开启监视index.ts单个文件

// 需要添加tsconfig.json配置文件,ts根据他的信息来对代码进行编译
tsc // 自动编译目录下所有ts文件
// tsconfig.json 中includes用来指定哪些ts文件需要被编译
/**
"include"指定哪些ts文件需要被编译 路径 ** 表示任意目录,*表示任意文件
"exclude"不需要被编译的文件目录
"extends"定义被集成的配置文件
"files"指定被编译文件的列表,只有需要被编译的文件少是才会用到
*/
{
  "include": [
    "./src/**/*"
  ],
  "exclude": [
    "./src/index/**/*"
  ],
  "files": [
  	"index.ts"
  ],
  "compilerOptions": {
    // target 指定ts文件被编译的版本
    // 可选值'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'es2021', 'es2022', 'esnext'
    "target": "ES3",
    // module 指定使用模块化的规范
    // 可选值'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'es2022', 'esnext', 'node16', 'nodenext'
    "module": "System",
    // lib指定项目中要使用的库, 一般不需要动
    // 可选值'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'es2021', 'es2022', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2019.intl', 'es2020.bigint', 'es2020.date', 'es2020.promise', 'es2020.sharedmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'es2020.number', 'es2021.promise', 'es2021.string', 'es2021.weakref', 'es2021.intl', 'es2022.array', 'es2022.error', 'es2022.intl', 'es2022.object', 'es2022.sharedmemory', 'es2022.string', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise', 'esnext.weakref'
    "lib": ["ES6",  "DOM"],
    // outdir指定编译后文件所在目录
    "outDir": "./dist",
    // outFile将quan代码合并为一个文件 仅支持 "amd" 和 "system" 模块
    "outFile": "./dist/app.js",
    // allowJs是否对js文件进行编译,默认为false
    "allowJs": true,
    // checkJs是否检查js代码是否符合语法规范,默认是false
    "checkJs": false,
    // removeComments是否移除注释
    "removeComments": true,
    // noEmit不生产编译后的文件
    "noEmit": false,
    // noEmitOnError当有错误的时候不生成编译后的文件
    "noEmitOnError": false,
    // alwaysStrict设置编译后文件是否开启严格模式,默认false
    "alwaysStrict": false,
    // noImplicitAny不允许隐式any类型
    "noImplicitAny": true,
    // noImplicitThis不允许不明确类型的this
    "noImplicitThis": true,
    // strictNullChecks严格检查空值
    "strictNullChecks": false,
    // strict所有严格检查的总开关
    "strict": false
  }
}

四、使用webpack打包ts代码

npm init -y // 对项目进行初始化(注意文件名不能含中文,否则会报错)
npm i -D webpack webpack-cli typescript ts-loader
// package.json
{
  "name": "05webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "ts-loader": "^9.4.2",
    "typescript": "^4.9.3",
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.0"
  }
}
// webpack.config.js
const path = require('path');
// webpack中所有的配置信息都应该卸载module.exports中
module.exports = {
    entry: './src/index.ts',
    output: {
        // 指定打包文件的目录
        path: path.resolve(__dirname, 'dist'),
        // 打包后的文件
        filename: "bundle.js"
    },
    module: {
        // 指定要加载的规则
        rules: [
            {
                // test指定的规则生效的文件
                test: /\.ts$/,
                // 要使用的loader
                use: 'ts-loader',
                exclude: /node-module/
            }
        ]
    }
}

// 执行 npm run build 进行打包

五、面向对象(oop)

所有的操作都要通过对象去操作就是面向对象编程。计算机程序本质就是对现实事物的抽象(比如一张照片就是对一个具体的人的抽象),一个事物到了程序中就变成了一个对象。
在程序中所有的对象都被分成了两部分数据和功能,以人为例,人的姓名、性别、年龄、身高、体重等属于数据,人可以吃饭睡觉打豆豆等属于人的功能;数据在对象中被称为属性,而功能就被称为方法,所以简而言之,在程序中万物皆对象。

5.1 类(class)

要想面向对象,操作对象,首先要使用对象,那么下一个问题就是如何创建对象。要创建对象,必须先定义类,所谓的类可以理解为对象的模型,程序中可以根据类创建指定类型的对象。不同的类创建不同的对象,person类创建人的对象,car类创建汽车的对象等等。

5.1.1 属性和方法

// 使用class关键字来定义类
// 对象中主要包含两部分:属性 方法
class Person {
    // 属性
    // 实例属性:直接定义 通过对象的实例访问
    readonly name : string = '艾斯';
    // 类属性(静态属性):在属性前使用static关键字定义 直接通过类访问
    static readonly age : number = 18;

    // 方法
    sayHello() {
        console.log('hihihi');
    }
    // 静态方法 直接通过类去调用
    // static sayHello() {
    //     console.log('hihihi');
    // }
}
const per = new Person()
console.log(per.name); // 艾斯
console.log(Person.age); // 18
// per.name = '路飞';
// console.log(per.name);  // 路飞
// 加上readonly开头的属性,只读无法修改
// per.name = '萨博' // 报错 无法分配到 "name" ,因为它是只读属性。

per.sayHello()
// Person.sayHello()

5.1. 2 构造函数

class Dog {
    // name = "招财";
    // age =8;
    name: string;
    age: number;
    // constructor()被称为构造函数 会在对象创建时调用 对属性进行初始化
    constructor(name:string, age:number) {
        console.log(this); // 在实例方法中,this就表示当前的实例对象
        // 在构造函数中当前对象就是当前新建的那个对象
        // 可以通过this向新建的对象中添加属性
        this.name = name;
        this.age = age; 
    }

    bark() {
        alert('wangwangwang~');
        // 在方法中可以通过this来表示当前调用方法的对象
        console.log(this);
        console.log(this.name);
        
    }
}
const dog1 = new Dog("小黑", 2);
const dog2 = new Dog("小白", 3);
console.log(dog1);
console.log(dog2);
dog1.bark()

5.1.3 继承

 // 父类 
    class Animal {
        name: string;
        age: number;
        constructor(name:string, age:number) {
            this.name = name;
            this.age = age;
        }
        sayHello() {
            console.log("动物在叫");  
        }
    }

    //使Dog继承Animal类 可以在不修改父类的基础上进行扩展
    // 使用继承后子类会继承父类的所有方法和属性 通过继承可以将多个类共有的代码卸载一个父类中 
    class Dog extends Animal{
        // 添加父类没有的方法
        run () {
            console.log(`${this.name}在咆哮`);
        }
        // 如果在子类中添加了和父类相同的方法,子类会覆盖掉父类的方法,这称作为方法的重写
        sayHello() {
            console.log('wangwangwang~');
        }
    }

    //使Cat继承Animal类
    class Cat extends Animal{
        
    }

    const dog1 = new Dog("旺财", 5)
    console.log(dog1);
    dog1.sayHello()
    dog1.run()

    const cat1 = new Cat("招财", 6)
    console.log(cat1);
    cat1.sayHello()

super

    class Animal {
        name: string;
        constructor(name:string) {
            this.name = name
        }
        sayHello() {
            console.log('miaomiaomiao~~');
        }
    }
    class Cat extends Animal {
        age: number;
        constructor(name: string, age: number) {
            // 如在子类中写构造函数,在子类构造函数必须父类的构造函数进行调用
            super(name); // 调用父类的构造函数
            this.age = age
        }
        sayHello() {
            //在类的方法中super表示当前类的父类
            super.sayHello()
        }
    }
    const cat = new Cat("大黑", 9)
    console.log(cat);
    cat.sayHello()

5.1.4 抽象类、抽象方法abstract

    // abstract抽象类与其他类区别不大,只是不能用来创建对象
    // 抽象类就是用来被继承 生下来就是当爸爸的
    abstract class Animal {
        name: string;
        constructor(name: string) {
            this.name = name
        }
        // 抽象方法 没有方法体;抽象方法只能定义在抽象类中,子类必须UI抽象方法进行重写
        abstract sayHello(): void;
    }
    class Cat extends Animal {
        age: number;
        constructor(name: string, age: number) {
            super(name);
            this.age = age
        }
        sayHello() {
           console.log("miaomiaomiaomiao~~~");
        } 
    }
    const cat = new Cat("大黑", 9)
    cat.sayHello()
    // const haha = new Animal() // 报错 无法创建抽象类的实例

5.1.5 接口

    // 接口用来定义一个类的结构,用来定义一个类应该包含哪些属性和方法
    // 接口可以在定义类的时候去限制类的结构,接口中的所有制都不能有实际值,接口值定义对象的结构,而不考虑实际值
    // 在接口中所有方法都是抽象方法
    interface myInterface {
        name: string;
        age: number;
    }
    interface myInterface {
        sex: string
    }
    const face: myInterface = {
        name: 'hhh',
        age: 12,
        sex: '男'
    }

    // 定义类时可以使用类去实现一个接口 接口其实就是一个限制
    interface myInter {
        name: string;
        sayhello(): void;
    }
    class myClass implements myInter {
        name: string;
        constructor(name: string) {
            this.name = name;
        }
        sayhello(): void {
            console.log("nihaoyaaaa");
        }
    }

5.1.6 封装

public:修饰的属性可以再任意位置被访问(修改) 默认值;
private:只能在类内部进行访问修改,通过在类中添加方法使得私有属性被外部访问

    class Person{
        // ts中可以再施行前添加属性的修饰符
        private name : string;
        private age: number;
        constructor(name:string, age: number) {
            this.name = name;
            this.age = age;
        }
        // // getter、setter方法用来设置属性 被称为属性的存取器
        // // 定义方法,用来获取name属性 
        // getName() {
        //     return this.age
        // }
        // // 设置方法,用来设置name属性
        // setName(value: number ) {
        //     // 判断年龄是否合法
        //     if(value >= 0) {
        //         this.age = value
        //     }
        // }

        // Ts中设置getter方法的方式
        get _age() {
            console.log('get执行了');
            return this.age
        }
        set _age(value: number) {
            console.log('set执行了');
            if(value >= 0) {
                this.age = value
            }
        }
    }
    const per = new Person('路飞', 11)
    // console.log(per._age);
    per._age = -11; // 不合法修改不了
    console.log(per._age);
    
    // 属性是在对象中设置的,属性可以再任意的被修改
    // 属性可以任意被修改将会导致对象中的数据变得非常不安全
    // per.name = '艾斯';
    // per.setName(12)
    // // per.age = 23; // 报错 属性“_age”为私有属性,只能在类“Person”中访问
    // console.log(per.getName());
    // console.log(per);
    console.log();

protected:受保护的属性,只能在当前类和当前类的子类中使用

class A {
        protected num: number;
        constructor(num: number) {
            this.num = num
        }
    }
    class B extends A {
        test() {
            console.log(this.num);
        }
    }
    const b = new B(345)
    b.num = 22 // 报错 属性“num”受保护,只能在类“A”及其子类中访问

简化

class C {
        // 直接将属性定义在构造函数中
        constructor(public name: string, public age : number) {
        }
    }
    const c = new C('xixxi', 12)

5.1.7 泛型

// 在定义函数或者类时,如果遇到类型不明确就可以使用泛型
function fn<T>(a: T): T {
    return a
}
// 在函数执行的时候才能确定是什么类型

// 可以直接调用具有泛型的函数
let result = fn(10);// 不指定泛型,ts可以自动对泛型进行判断
let result2 = fn<string>('hello') // 指定泛型

function fn2<T, K>(a: T, b: K):T {
    console.log(b);
    return a
}
fn2<number, string>(55, 'world') 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值