TypeScript

简介

TypeScript是什么

  • 以js为基础构建的语言
  • 一个js的超集
  • 可以在任何支持js平台中支持
  • ts扩展了js,并添加了类型
  • ts不能被js解析器直接执行

编译ts文件:tsc

TypeScript增加了什么

  • 类型
  • 添加ES不具备的新特性
  • 支持ES的新特性
  • 丰富的配置选项
  • 强大的开发工具

基本类型

=> 将js变成静态类型语言

let a:number; //声明一个变量a,同时指定它的类型为number

a = 'hello'; //此行代码会报错

类型声明

类型声明是TS非常重要的一个特点;通过类型声明可以指定TS中变量(参数、形参)的类型;

指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错(即使报错也会正常编译);

简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值;

let 变量: 类型;
let 变量: 类型 = 值;

//参数的类型以及返回值的类型
function fn(参数: 类型, 参数: 类型): 类型{
    ...
}

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

自动类型判断

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

let a = 1;

a = '123' //报错

字面量进行类型声明

let a: 10;  //限制值只能是10

a = 11;  //报错

//这样比较好用

let b: 'male' | 'female';

let c: boolean | string;

各种类型

一个变量设置为any后,相当于对该变量关闭了TS的类型检测;所以在使用中不建议用any。

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

any和unkown

any可以赋值给任意变量,unkown不可以随便赋值给其他变量(只霍霍自己)

let s:string;

let a; //默认声明不定义类型就是any

s = a; //不会报错

let e:unknown;
e = 10;

let a = '234'

a = e; //报错

如果非要赋值,在赋值之前加个判断语句

let e:unknown;
e = 10;

let a = '234'

if(typeof e === 'string') {
  s = e
}

类型断言

用来告诉解析器变量的实际类型

语法:
    变量 as 变量
    <类型>变量

s = e as string;   //告诉编译器e就是字符串,别报错!

s = <string>e;

viod

void用来表示空,以函数为例,就表示没有返回值的函数

function fn():viod {

}

never

never表示永远不会返回结果

function fn():never {

        throw new Error('报错了');

}

js中有一种函数就不返回结果,连undefined都不返回,是用来报错的。
程序报错=>代码结束=>没有返回值。

Object

表示一个js对象

let a: object;

a = {}

a = function() {}

{}用来指定对象中可以包含哪些属性

let b: {name: string};

b = {} //会报错,里边必须有name,且多了也不行

b = {name:'hui',age:19} //也会报错

b = {name:'sun'}

let c:{name:string,age?:number}; //问号代表属性可选,加不加都行

c = {name:'123'}

c = {name:'1233',age:17}

let d: {name:string,[propName:string]: any}

d = {name:'456',age:18,render:'男'}

中括号里边 : propName可以为任意字符串(js属性名都是字符串)

设置函数结构的类型声明

let e: Function

let f: (a,b) => number; //表示希望f是一个函数,后边是类型声明,但是只能是两个参数,三个会报错

Array

let e:string[];  //表示字符串数组

e = ['a','w']

let g:Array<number>

g=[1,2,3]

tuple

元组:固定长度的数组

let h:[string,string] //表示创建了一个元组,里边俩值都是string类型

enum

枚举:把所有可能的情况列出来

Enum Gender {

        male = 0,

        female = 1

}

let i: {name:string,gender:Gender};

i = {
        name:'sun',

        gender:Gender.male  //会直接存储0

}

表示类型的时候不仅有或(|),还有和(&)

let j:string & number ;  //可以但是毫无意义

let i: {name: string} & {age: number}

类型别名

let k: 1 | 2 | 3;

let l : 1 | 2 | 3;

type myType = string;

let m:myType;  //相当于let m:string

type yourType = 1 | 2 | 3;

let k :yourType

编译选项

tsc app.ts 改一次就要重新编译一次 => tsc app.ts -w 编译器会自动监视文件变化

根据配置文件 tsconfig.json 让tsc编译所有文件

tsconfig.json

是ts编译器的配置文件,可以根据它的信息来对代码进行编译,可以写注释

{
  "include":[
    //一个*表示任意文件,两个**表示任意目录
    "./src/**/*"
  ],
  "exclude":[
    "./src/hello/**/*"
  ],
  "files": [
    "core.ts",
    "sys.ts",
    "types.ts",
    "scanner.ts",
    "parser.ts",
    "utilities.ts",
    "binder.ts",
    "checker.ts",
    "tsc.ts"
  ],
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true
  }

}

include:包含

定义希望被编译文件所在的目录

exclude:不包含

定义需要排除在外的目录

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

extend:继承

定义被继承的配置文件

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

files:列表

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

compilerOptions:编译器选项

编译选项是配置文件中非常重要也比较复杂的配置选项

在compilerOptions中包含多个子选项,用来完成对编译的配置

项目选项

target:设置ts代码编译的目标版本(ES3(默认)、ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext)

module:设置编译后代码使用的模块化系统(CommonJS、UMD、AMD、System、ES2020、ESNext、None)

lib:指定代码运行时所包含的库(宿主环境)(ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext、DOM、WebWorker、ScriptHost ) => 一般不动

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

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

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

allowJs:是否对js文件编译

checkJs:是否对js文件进行检查

removeComments:是否删除注释,默认false

noEmit:不生成编译后的文件,默认false

noEmitOnError:当有错误时不生成编译后的文件,默认false

sourceMap:是否生成sourceMap,默认false

alwaysStrict:设置编译后的文件是否使用严格模式,默认false

noImplicitAny:不允许隐式any类型

noImplicitThis:不允许隐式类型的this

strictNullChecks:严格的空值检查

strict:所有严格检查的总开关,为true则全开

使用webpack打包代码

export.modules = {
    ...
    module:{
        rules:[
            {
                test:/\.ts$/,
                use:'ts-loader',
                exclude:/node-modules/
            }
        ]
    }
}

 面向对象

class 类名 {
    属性名: 类型;
    
    constructor(参数: 类型){
        this.属性名 = 参数;
    }
    
    方法名(){
        ....
    }

}

对象中包含属性和方法

class Person {
    //定义实例属性:需要通过对象实例访问
    //const per = new Person() per.name
    name:string = 'sun';

    //定义类属性(静态属性):无需创建对象,通过类访问
    //Person.age
    static age:number = 18;
}

构造函数

class C{
    name: string;
    age: number

    constructor(name: string, age: number) {
        //this就是当前对象
        this.name = name;
        this.age = age;
    }
}

继承

使用继承后,子类将会拥有父类所有的方法和属性

通过继承可以将多个类中共有的方法和属性写在一个父类中

如果子类中添加了和父类相同的方法,则子类会覆盖掉父类的方法。这种形式称为方法的重写。

super关键字

父类也叫超类

在类的方法中,super表示父类

class Animal {
    name:string;

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

    sayHello(){
        console.log('动物在叫')
    }
}

class Dog extends Animal {
    sayHello(){
        //就是在调用父类的sayHello
        super.sayHello()
    }
}

如果在子类中使用了构造函数,相当于把父类的构造函数给覆盖掉了,父类中的属性就无了。

子类的构造函数中必须对父类的构造函数进行调用 => super()

抽象类

以abstract开头的类就是抽象类,和其他类差别不大,只是不能用来创建对象

抽象类是专门用来继承的类,抽象类中可以添加抽象方法。

抽象方法使用abstract开头,没有方法体,只能定义在抽象类中,并且子类必须对抽象方法进行重写。

接口

用来定义一个类结构

type myType = {
    name:string,
    age:number
}

interface myInterface {
    name:string;
    age:number;
}

const obj:myInterface = {
    //多一个少一个都报错,跟类型定义很像
    name:'sss',
    age:111
}

用来定义一个类中应该包含哪些属性和方法,同时接口也可以当成类型声明去使用。

和类型声明的区别:接口可以重复声明,最后是所有的接口的并集。

接口可以在定义类的时候去限制类的结构,在这一点有点像抽象类。

//接口中所有的属性都不能有实际的值,只定义对象结构不考虑实际值
interface myInter {
    name:string;
    sayHello():void;
}

在抽象类中可以有具体的方法也可以不,接口中都是抽象方法

使用implements实现接口

interface myInter {
    name:string;
    sayHello():void;
}


class MyClass implements myInterface {
    //必须把接口里所有的属性和方法在这里实现
    name:string;
    constructor(name:string) {
        this.name = name
    }

    sayHello() {
        console.log('xxx')
    }
}

接口实际上就是定义了一个规范,对类的限制

属性封装

属性可以任意修改将会导致对象中的数据变得不安全

public属性 => 可以在任意位置访问(修改) 默认值

private属性 => 私有属性只能在类内部进行访问(修改),子类也不行 => 通过在类中添加方法使得私有属性可以被外部访问

protect属性 => 受保护的属性,只能在当前类和当前类的子类中访问。

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

    constructor(name:string,age:number) {
        this.name = name;
        this.age = age;
    }
    //定义方法获取name属性
    getName() {
        return this.name
    }

    //定义方法设置name属性
    setName(value:string) {
        this.name = value
    }
}

const per = new Person('sun',18)

//想要获取属性值需要调用getName方法
console.log(per.getName())
//想要修改属性值必须调用setName方法
per.setName('hui')

getter和setter被称为属性的存取器

Ts中设置getter方法方式

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

    constructor(name:string,age:number) {
        this.name = name;
        this.age = age;
    }
    
    get name() {
        return this.name
    }
    set name(value:string) {
        this.name = value
    }
}

const per = new Person('sun',18)

//per.name不是寻找name属性,而是执行get name方法
console.log(per.name)
console.log(per.name('hui'))

定义类的简要写法,直接将属性定义在构造函数中

class C{
    constructor(public name:stirng,public age:number) {
    }
}
等价于
class C{
    name:string;
    age:number;

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

泛型

在定义函数或者类时,如果遇到类型不明确的时候就可以使用泛型

要根据调用的情况得到结论

<T>就是泛型

function fn<T>(a:T):T {

        return a

}

可以直接调用具有泛型的函数 =>

fn(10);  //不指定泛型,Ts类型自动推断

fn<string>(‘hello')   // 指定泛型

泛型可以指定多个

表示泛型T必须是Inter的实现类(子类)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值