TypeScript

1.TypeScript是什么?

  • 以JavaScript为基础构建的语言
  • 是JavaScript的超集
  • 可以在任何支持JavaScript的平台中执行
  • TypeScript扩展了JavaScript,并添加了类型
  • TS不能被JS解析器直接执行,需要将TS编译成JS

2.TypeScript开发环境搭建

1.下载并安装Node.js

2.使用npm全局安装typescript

        npm i -g typescript

3.创建一个ts文件

4.使用tsc对ts文件进行编译

  • 进入命令行
  • 进入ts文件所在目录
  • 执行命令:tsc xxx.ts

3. 基本类型

1.类型声明

  • 类型声明是TS非常重要的一个特点                                  
  • 通过类型声明可以指定TS中变量(参数、形参)的类型
  • 指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则会报错
  • 简言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值

2.自动类型判断

  • TS拥有自动的类型判断机制
  • 当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
  • 所以当变量的声明和赋值同时进行,可以省略掉类型声明

3.类型

类型例子描述
number1,-3,2.5任意数字
string’hello‘,hello任意字符串
booleantrue 、 false布尔值
字面量其本身限制变量的值就是该字面量的值
any*任意类型
unknown*类型安全的any
void空值(undefined)没有值(或undefined)
never没有值不能是任何值
object{name:'佩奇'}任意js对象
array[1,2,3]任意js数组
tuple[4,5]元素,TS新增类型,固定长度的数组
enumenum{A,B}枚举,TS中新增类型
//声明一个变量a,同时指定它的类型为number
let a: number;

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

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

let c = false;//变量的声明和赋值同时进行,可以省略类型说明,TS会自动进行类型检测
c = true;
// c = 123;报错

//在JS中,函数不考虑参数的类型和个数,TS中略有不同
function sum(a, b) {
    return a + b;
}

sum(123, 456)//579
sum(123,'456')//'123456'

//规定了sum2参数类型和返回值类型都是number
function sum2(a:number, b:number):number {
    
    // return a + "hello" 返回值类型错误

    return a + b;
}

sum2(123, 456) //579
// sum2(123,'456')报错,类型
// sum2(123,456,789)报错,个数

let d: 10; //使用字面量进行类型声明,类似于常量,只能是10,不能改变
d = 10;
// d = 11; 报错

// 可以使用 | 来连接多个类型(联合类型)
let e: "male" | "female";
e = "male";
e = "female";

let f: boolean | string; //联合类型
f = true;
f = "hello"

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

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

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

//但是any和unknown是有区别的
let i: string;
i = g //g的类型是any,它可以赋值给任意变量

h = "hi"//上面已经规定h为unknown类型
//unknown实际上就是一个类型安全的any,unknown类型的变量不能直接赋值给其他变量
// i = h   报错
//但是可以提前判断
if (typeof h === 'string') {
    i = h;
}

//还可以类型断言:用来告诉解析器变量的实际类型
//此处是告诉解析器 h就是字符串类型 (以下两种写法均可)
/* 
类型断言语法
    变量 as 类型
    <类型>变量
*/
i = h as string;
i = <string>h

//void表示空,以函数为例,就表示没有返回值的函数
function fn():void{
    //return 123 报错
    //return "hello" 报错
    //return 可
    //return undefined 可
    //return null 可
    //没有return,可
}
//never表示永远不会返回结果
function fn2(): never{
}
function fn3(): never{
    throw new Error("报错了")//永远不会返回结果
}

//object表示一个js对象
let ab: object;
ab = {};
ab = function () { };//函数也是object

//{}用来指定对象中可以包含哪些属性
//语法:{属性名:属性值,属性名:属性值}
let ac: { name: string }
// ac = {} 报错
// ac = {name:'佩奇',age:10} 报错,结构必须与指定的一样,多了少了都不行
ac = { name: '佩奇' }

//在属性名后边加上?,表示属性是可选的
let ad: { name: string, age?: number }
ad = { name: '佩奇', age:10}
ad = { name: '佩奇' }

//[propName: string]: any 表示任意类型的属性  propName可更改成其他字段,非固定写法
let ae: { name: string, [propName: string]: any }
ae = { name: '猪八戒', age: 10, gender: '男' }

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

//数组的类型声明 1.类型[] 2.Array<类型>
//string[] 表示字符串数组
let ag: string[]
ag = ['a','b']
//number[] 表示数值数组  
let ah: number[]
ah = [1, 2, 3]
//Array<number> 也表示数值数组
let aj: Array<number>
aj = [1, 2, 3]

// 元组:固定长度的数组
//语法 [类型,类型,类型]
let ak: [string, string]
ak = ["li", "wang"]

// enum 枚举
enum Gender{
    male,
    female
}
let bb: { name: string, gender: Gender }
bb = { name: "猪八戒", gender: Gender.male }

console.log(bb.gender == Gender.male) //true

//& 表示“且”
let bc: { name: string } & { age: number }
bc = { name: '佩奇', age: 10 }

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

4.编译选项

1.自动编译文件

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

tsc xxx.ts -w

2.自动编译整个项目

1.在项目根目录下创建ts的配置文件tsconfig.json

        可以使用命令tsc -init

 2.添加配置文件后,只需要直接使用tsc命令即可完成对整个项目的编译

 3.配置选项 

{
      /*
        ts编译器会根据tsconfig.json的配置对代码进行编译
        "include"用来指定哪些ts文件需要被编译
         路径:** 表示任意目录
                * 表示任意文件
        "exclude"不需要被编译的文件目录
        默认值:['node_modules','bower_components','jspm_packages']
      */
    
      "include":[
         "./src/**/*" 
      ],  

      "exclude":[
         "./src/hello/**/*" 
      ],  
        //编译器的选项
       "compilerOptions":{
            //target用来指定ts被编译为的ES的版本
            "target": "es2016", 
            //lib用来指定项目中要使用的库                               
            // "lib": [],
            // module指定要使用的模块化规范
            "module": "commonjs", 
            //outDir用来指定编译后文件所在的目录
            // "outDir": "./", 
            //设置outFile后,所有的额全局作用域中的代码会合并为一个文件
            //所有严格检查的总开关,为true时,其他严格检查自动开启,为false其他严格检查自动关闭
            "strict": true, 
            // "outFile": "./app.js",
            //是否对js文件进行编译,默认为false
            // "allowJs": true,
            //是否检查js代码是否符合语法规范,默认为false
            // "checkJs": false,
            //是否移除注释,默认为false
            // "removeComments": true, 
            //不生成编译后的文件,默认为false
            // "noEmit": true,
            // 当有错误时不生成编译后的文件
            // "noEmitOnError": true, 
            //用来设置编译后的文件是否使用严格模式,默认为false
            // "alwaysStrict": true, 
            //不允许隐式的any类型
            // "noImplicitAny": true,
            //不允许不明确类型的this
            // "noImplicitThis": true,
            //严格的检查空值
            // "strictNullChecks": true,
        } 



}

5.类

1.类的简介

使用class关键字来定义一个类

对象中主要包含两部分:属性和方法

class Person{

    /*
       
    直接定义的属性是实例属性,需要通过对象的实例去访问
    const per = new Person()
    per.name

    使用static开头的属性是静态属性(类属性),可以直接通过类访问
    Person.age

    readonly开头的属性表示一个只读的属性 无法修改

    */

    //定义实例属性
    name = "贾宝玉"
    //在属性前使用static关键字可以定义类属性(静态属性)
    static age = 18
    readonly job = 'teacher'

    //定义方法
    //如果方法以static开头则方法就是类方法,可以直接通过类去调用
    sayHello(){
        console.log('Hello!')
    }

}

const per = new Person();
console.log(per)

2.构造函数和this:

class Dog{
    name:string;
    age:number;
    //constructor被称为构造函数
    //构造函数会在对象创建时调用
    constructor(name:string,age:number){
        //在实例方法中,this就表示当前的实例
        //在构造函数中当前对象就是当前新建的那个对象,可以通过this向新建的对象中添加属性
        this.name = name
        this.age = age
    }
    bark(){
        alert('汪汪汪!')
        //在方法中可以通过this来表示当前调用方法的对象,谁调用,this就是谁
        console.log(this);
        
    }
}
const dog1 = new Dog('小黑',10)
const dog2 = new Dog('小白',2)
dog2.bark()//bark里的this为dog2

3.继承

//继承
class Animal{
    name:string;
    age:number;
    constructor(name:string,age:number){
        this.name = name
        this.age = age
    };
    sayHello(){
        console.log('动物在叫!');
        
    }
}
/**
 * Cat extends Animal
 *  -此时,Animal被称为父类,Cat被称为子类
 *  -使用继承后,子类将会拥有父类所有的方法和属性
 *  -通过继承可以将多个类中共有的代码写在一个父类中,这样只需写一次即可让所有的子类都同时拥有父类中的属性和方法
 *  -如果希望在子类中添加一些父类中没有的属性或方法,直接加就行
 *  -如果在子类中添加了和父类相同的方法,则子类方法会覆盖掉父类方法(方法重写)
 */
class Cat extends Animal{
    eat(){
        console.log(`${this.name}吃鱼`);
        
    }
}
class Pig extends Animal{
    color:string;
    //如果在子类中写了构造函数,在子类的构造函数中必须对父类的构造函数进行调用 用super
    constructor(name:string,age:number,color:string){
        super(name,age)//调用父类的构造函数
        this.color = color
    }
    sayHello(){
        //在类的方法中 super就表示当前类的父类 super.sayHello()调用的是父类的函数
        super.sayHello()
        
    }
}
const cat = new Cat('小花猫',2)
const pig = new Pig('佩奇',3)
cat.eat()

4.抽象类

//抽象类
/**
 * 以abstract开头的类是抽象类
 * 抽象类和其他类区别不大,只是不能用来创建对象,而是专门用来被继承的类
 * 抽象类中可以添加抽象方法
 */
abstract class Car{
    name:string;
    constructor(name){
        this.name = name
    }
    /**
     * 定义一个抽象方法
     * 抽象方法使用abstract开头,没有方法体
     * 抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写
     */
     abstract run()
}
class BenChi extends Car{
    run() {
        console.log('奔驰跑起来了');
        
    }
}
const car = new Car('车')//报错

6.接口

接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法

/**
 * 接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法,
 * 同时接口也可以当成类型声明去使用
 */
//类型别名,重复声明会报错
type newType = {
    name:string,
    age:number
}
type newType = {
    gender:string,
}
//接口,重复声明会合并,相当于myInterface里定义了三个属性
interface myInterface{
    name:string,
    age:number
} 
interface myInterface{
    gender:string,
}
const obj:myInterface = {
    name:'佩奇',
    age:1,
    gender:'男',
}
/**
 * 接口可以在定义类的时候去限制类的结构
 * 接口中所有的属性都不能有实际的值
 * 接口只定义对象的结构,而不考虑实际值
 * 接口中的所有方法都是抽象方法
 */
interface myInter{
    name:string,
    sayHello():void
}
/*定义类时,可以使类去实现一个接口
  实现接口就是使类满足接口的要求
*/
class Myclass implements myInter{
    name: string;
    constructor(name: string){
        this.name = name 
    }
    sayHello(){
        console.log('大家好');
        
    }
    
}

7.属性的封装

class Person{
    /**
     * public 修饰的属性可以在任意位置访问(修改)默认值 包括子类
     * private 私有属性,私有属性只能在类内部进行访问(修改)
     *        -通过在类中添加方法使得私有属性可以被外部访问
     * protected 受保护的属性 只能在当前类和当前类的子类中访问(修改)
     */
    // private name:string;
    // private age:number;
    _name:string;
    _age:number;
    constructor(name:string,age:number){
        this._name = name
        this._age = age
    }

    /**
     * 现在属性是在对象中设置的,可以任意被修改,导致对象中的数据变得很不安全
     */
    /**
     * getter方法用来读取属性
     * setter方法用来设置属性
     *      -他们被称为属性的存取器
     */
    //下面这种要通过调函数的方式per.getAge() per.setAge(10)
    getAge(){
        return this._age
    };
    setAge(value:number){
        if(value>=0){
            this._age = value
        }
    }
    //TS中设置getter setter的方式 可以直接.name来读取和调用 per.name = '猪八戒'
    get name(){
        return this._name
    }
    set name(value){
        this._name = value
    }
}        
const per = new Person('孙悟空',12)
// per.setAge(10)
per.name = '猪八戒'


class A{
    // num:number;//默认的修饰符为public
    // private num2:number;
    protected num3:number;
    constructor(num){
        this.num = num
        this.num2 = this.num2
        this.num3 = this.num3
    }
}
class B extends A{
    test(){
        // console.log(this.num);//可以访问
        // console.log(this.num2);//不能访问
        console.log(this.num3);//可以访问
    }
}

const b = new B(1)
console.log(b.num3);//不能访问

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

8.泛型

//泛型
function fnn<T>(a:T):T{
    return a
}
fnn(10) //不指定泛型,TS可以自动对类型进行推断
fnn('hello') //指定泛型

//泛型可以同时指定多个
function fnn2<T,K>(a:T,b:K):T{
    console.log(b);
    
    return a
}
fnn2<number,string>(10,'hello')
//定义一个接口
interface Inter{
    length:number
}
//T extends Inter 表示泛型T必须是Inter实现类(子类)
function fnn3<T extends Inter>(a:T):number{
    return a.length
}
class MyClass<T>{
    name:T;
    constructor(name:T){
        this.name = name
    }
}
const mc = new MyClass<string>('孙悟空')

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值