typescript-day2

141 阅读7分钟

一:编译选项

自动编译文件

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

tsc xxx.ts -w

自动编译整个项目

如果直接使用tsc或者tsc -w ,则可以自动将对当前项目下的所有ts文件编译成js文件

但是能直接使用tsc命令时,要先在项目根目录下创建tsconfig.json配置文件

tsconfig.json配置项

include:只编译那些目录下的文件

    // include:只编译那些目录下的文件
    // 默认值 ["**/*"]
    "include": ["test/**/*","src/**/*"]//表示只编译test和src文件下的ts文件

exclude:那些目录下的文件不会被编译

    // exclude:那些目录下的文件不会被编译
    // 默认值 ["node_modules", "bower_components", "jspm_packages"]
    "exclude":["dist/**/*"] //dist目录下的文件不会被自动编译

extends:定义被继承的配置文件

    "extends":"./base.json"

files:只编译那些文件,具体的文件

    "files": [
         "./test/test.ts"
    ]

compilerOptions:包含多个配置子项

"compilerOptions": {
        //编译后代码使用的模块化系统
        "module": "CommonJS",
        // 编译目标js版本
        "target":"ES6",
        //指定代码运行时所包含的库(宿主环境)
        "lib":["ES6","DOM"],
        //编译后js所在的目录
        "outDir": "dist",//编译后js文件会生成在dist目录
        //将所有ts文件集中编译到一个js文件
        "outFile": "dist/app.js",
        //指定代码的根目录
        "rootDir": "./src",
         // 是否对js文件编译
        "allowJs": true,
        //是否对js文件进行检查
        "checkJs": true,
        //是否删除注释
        "removeComments":false,
        // 不对代码进行编译
        "noEmit": false,
        //是否生成sourecMap
        "sourceMap": false
    }

严格检查

  • strict

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

    • 总是以严格模式对代码进行编译
  • noImplicitAny

    • 禁止隐式的any类型
  • noImplicitThis

    • 禁止类型不明确的this
  • strictBindCallApply

    • 严格检查bind、call和apply的参数列表
  • strictFunctionTypes

    • 严格检查函数的类型
  • strictNullChecks

    • 严格的空值检查
  • strictPropertyInitialization

    • 严格检查属性是否初始化
  • 额外检查

    • noFallthroughCasesInSwitch

      • 检查switch语句包含正确的break
    • noImplicitReturns

      • 检查函数没有隐式的返回值
    • noUnusedLocals

      • 检查未使用的局部变量
    • noUnusedParameters

      • 检查未使用的参数
  • 高级

    • allowUnreachableCode

      • 检查不可达代码

      • 可选值:

        • true,忽略不可达代码
        • false,不可达代码将引起错误
    • noEmitOnError

      • 有错误的情况下不进行编译
      • 默认值:false

二:webpack

实际开发中我们都需要使用构建工具对代码进行打包,TS同样也可以结合构建工具一起使用,下边以webpack为例介绍一下如何结合构建工具使用TS。

步骤:

1.初始化项目

进入项目根目录,执行 npm init -y,创建package.json

2.下载构建工具

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

共7个包 webpack :构建工具webpack

webpack-cli :webpack的命令工具

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

typescript : ts编译器

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

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

clean-webpack-pluhin :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测试' }), ] }

三:面向对象

1:类

定义属性和方法 属性分为静态属性和实例属性 区别就在于静态方法只有类可以调用,而实例属性只有类的实例对象可以调用

同理方法也分为实例方法和静态方法

class Fthan{
    // 实例属性
    name:string='fthanClass';
    // 静态属性,用关键字static定义静态属性(类属性)
    static age:number=24;

    // 定义实例方法
    getdata(){
        console.log("holle");
    }
    // 定义静态方法
    static getdataA(){
        console.log("holle A");
    }
}
var ft=new Fthan()

// 实例属性只能通过实例访问,ft就是Fthan类的实例
console.log(ft.name);

//静态属性只能通过类来访问
console.log(Fthan.age);

// 调用实例方法
ft.getdata()
// 调用类方法
Fthan.getdataA()

构造函数和this

class Fthan{
    name:string;
    age:number;
    //构造函数constructor,在new时此构造函数就会被执行
    constructor(x:string,y:number){
        // 这里的this就是当前的类
        // 可以通过this向新建的对象中属性然后赋值
        console.log(this);
        this.name=x;
        this.age=y;
    }
    asd(){
        // 实例方法中的this指向的是该方法的调用者。
        console.log(this);
    }
}
var ft=new Fthan('tsy',24);
var a=new Fthan('cjy',23)

ft.asd();

关键字

readonly:只读

class Fthan{
    // readonly关键字修饰的属性是只读的不可修改的
    readonly name:string;
    age:number;
    constructor(x:string,y:number){
        this.name=x;
        this.age=y;
    }
}
var ft=new Fthan('tsy',24);
// 因为在name属性前添加了readonly关键字,所以name不可修改
ft.name='lll' //报错,无法更改值

继承extends 子类继承父类采用就近原则,如果要访问或者调用的方法子类中存在,则直接访问子类中的属性或者方法。

class Father{
    name:string
    constructor(name:string){
        this.name=name
    }
    asd(){
        console.log('lllll');
    }
}
class Son extends Father{
    age:number=18;
}
let a=new Son('tsy');
console.log(a);
a.asd()
// 结果{name: 'tsy', age: 18}
// lllll

super 如果子类中存在constructor,那么子类的constructor中必须使用super继承父类中的constructor

class Father{
    name:string
    constructor(name:string){
        this.name=name
    }
    asd(){
        console.log('我是父类');
    }
}
class Son extends Father{
    age:number;
    constructor(name:string,age:number){
        super(name);
        this.age=age;
    }
    asd(){
        //super在子类中就表示父类的实例
        //在子类方法中通过super调用父类在被重写的方法
        super.asd()
    }
}
let a=new Son('tsy',23);
// 结果{name: 'tsy', age: 23}
a.asd()
// 结果 “我是父类”

public,protected,private修饰符

public:(默认) 在实例对象,子类,本身类中可更改

class Father{
    public name:string
    constructor(name:string){
        this.name='ppp'//自身中可更改
    }
}
class Son extends Father{
    constructor(name:string){
        super(name);
        this.name='asd'//子类中可更改
    }
}

let a=new Son('tsy');
a.name='qwe'//实例对象中可更改
// 结果 {name: 'qwe'}

protected:子类,本身类中可更改

class Father{
    protected name:string
    constructor(name:string){
        this.name='ppp'//自身中可更改
    }
}
class Son extends Father{
    constructor(name:string){
        super(name);
        this.name='asd'//子类中可更改
    }
}

let a=new Son('tsy');
a.name='qwe'//不可更改

private:本身类中可更改

class Father{
    private  name:string
    constructor(name:string){
        this.name='ppp'//自身中可更改
    }
}
class Son extends Father{
    constructor(name:string){
        super(name);
        this.name='asd'//子类中不可更改
    }
}

let a=new Son('tsy');
a.name='qwe'//不可更改

属性存取器

对于一些不希望被任意修改的属性,可以将其设置为private 属性设置为private,则改该属性则无法被外界访问或者修改 怎样通过外界访问或进行赋值修改呢?

方法:读取属性的方法叫做setter方法,设置属性的方法叫做getter方法

class Father{
    private _name:string;
    constructor(name:string){
        this._name=name 
    }
    get name(){
        return this._name
    }
    set name(name:string){
        this._name=name
    }
}

let a=new Father('tsy');
a.name='asd'//触发setter
console.log(a.name); //触发getter
console.log(a);
//打印结果{_name: 'asd'}

抽象类

关键字abstract

什么是抽象类,抽象类和其他类差不多,但是抽象类是不可被new的

说白了,抽象类的出现就是为了给其他类继承的爸爸类

此外抽象类还有一个抽象方法

abstract class Fthan{
    name:string;
    constructor(name){
        this.name
    }
    // 抽象方法
    // 使用abstract关键字。切没有返回值
    // 抽象方法的意义就是为了,子类必须对其重写
    abstract getdata():string;
    abstract setdata():void;

}

class Son extends Fthan{
    getdata(){
        return '重写的方法'
    }
    setdata(){
        console.log('重写的方法');
    }
}

接口

关键字:interface 接口和抽象类很相似,接口中的所有属性和方法都是抽象的,没用具体的值。接口主要负责定义一个类的结构,限制一个对象的结构。

interface Person{
    name:string;
    fun():void;
}
// 定义一个类的结构
class Son implements Person{
    name='';
    constructor(name:string){
        this.name=name
    };
    fun(){
        console.log('lll');
    }
}
let obj1=new Son('tsy')

// 限制一个对象的内部结构
let obj:Person = {
    name:'tsy',
    fun:()=>{
        console.log(';;;');
    }
}
obj.fun()

只读 关键字 readonly

只有在对象刚刚被创建的时候给其赋值

interface Person{
    name:string;
    readonly age:number;
}

let obj:Person = {
    name:'sty',
    age:24
}
obj.age=25 //error

任意/可选

interface Person{
    name:string;
    age?:number;
    [arr1:string]:any;
}

let obj:Person={
    name:'tsy',
}
let obj1:Person={
    name:'tsy',
    age:24
}
let obj2:Person={
    name:'tsy',
    sex:'男'
}

接口和类型别名的区别

接口

interface Person{
    name:string;
    age:numder;
};
interface Son{
    (x:number): void;
};

类型别名

type Tsy={
    name:string,
    age:number
};
type Fun = (x:string)=>void;

泛型

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

function fn<T>(a:T):T{
    return a;
}
let res=fn(10);//不指定泛型,TS可以对类型进行推断
let res2=fn<string>('sss'); //指定泛型

//泛型可同时指定多个
function fn2<T,K>(a:T,b:K):T{
    console.log(b);
    return a;
}
fn2<string,number>('123',1);

//T extends Inter 表示泛型T必须是Inter的实现类(子类)
interface Inter{
    length:number
}
function fn3<T extends Inter>(a:T):number{
    return a.length;
}
console.log(fn3({length:10}));

//类也可以使用泛型
class MyClass<T>{
    name:T;
    constructor(name:T){
        this.name=name;
    }
}

const mc=new MyClass<string>('tsy')