typescript

一、介绍

1.typescript是由微软开发的一款开源的编程语言

2.ts是js的超级,拓展了js语法,更像java/c#这样面向对象语言,更适合开发大型项目。

3.谷歌也在大力支持ts,谷歌的angular2x+ 就是基于ts语法的。

4.最新的Vue ,React 也可以集成ts。

二、安装和编译

1.安装:npm install -g typescript

2.生成配置文件:tsc --init  创建tsconfig.json 文件(eg:可修改输出地址“outDir”:“./js”,等配置)

3.编译:tsc hello.ts  (hello.ts 是自己建的ts名)

4.点击菜单栏 任务-运行任务  点击tsc 监视-tsconfig.json ,然后就可以自动生成代码了。

三、ts的数据类型

1.布尔类型(boolean)

2.数字类型(number)

3.字符串类型(string)

4.数组类型(array)

5.元祖类型(tuple)

6.枚举类型(enum)

7.任意类型(any)

8.null 和 undfined

9.void 类型

10.never类型

四、各类型的用法

1.布尔类型(boolean)

let flag:boolean = true;
flag =false;

2.数字类型(number)

let num:number;
num =3;

3.字符串类型(string)

let str:string = '';
str = 'I am string';

4.数组类型(array)

let arr:string[]=[];
arr = ['1','2','3','4'];
or
let arr:Array<number> =[1,2,3,4];

5.元祖类型(tuple)

//已知数组元素的个数,并且知道每个元素的类型
let tupleArr :[string,number] =['lalala',2];

6.枚举类型(enum)

enum Color{
    red = 1,
    blue,
    orange = 5,
    green = 7
}
let redNum:Color = Color.red   //1
let blueNum:Color = Color.blue    //2
let orangeNum:Color = Color.orange    //5

let red:string = Color[1]   //red
let blue:string = Color[2]    //blue
let orange:string = Color[5]    //orange

7.任意类型(any)

let notSure:any = 4; 
notSure = 'maybe a string instead';
notSure = false; //okay

8.null 和 undfined

    //strictNullChecks标记的启用是在tsconfig.json文件里进行配置。
// {
//     "compilerOptions": { //编译选项,可以被忽略,这时编译器会使用默认值
//         "strictNullChecks": false, //在严格的null检查模式下,null和undefined值不包含在任何类型里,只允许赋值给void和本身对应的类型。
//     }
// }
//"strictNullChecks": false,
//默认情况下,null 和 undefined 是其它类型的子类型,可以赋值给其它类型,如number类型,此时,赋值后的类型会变成 null 或 undefined。
let hh: number;
hh = null; //ok的
hh = undefined;  //ok的

//"strictNullChecks": true,
let ss: number;
ss = null; //提示不可以
ss = undefined;  //提示不可以

//定义没有赋值就是undifined;
let aa :string | undifined;
console.log(aa) //undefined

//一个元素可能是number,null,undifined
let num: number | null | undefined
num=123;

9.void 类型

//表示方法没有返回任何类型
function run(): void {
    console.log(111);

}
run()
//表示传参是number类型,函数返回值也是number类型
function sum(num:number): number {
    console.log(111);
    return num + 123
}
sum(12);

10.never类型

//never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。
// 即使 any也不可以赋值给never。通常表现为抛出异常或无法执行到终止点(例如无线循环)。比如:
let x: never; let y: number; // 运行错误,数字类型不能转为 never 类型 x = 123; // 运行正确,never 类型可以赋值给 never类型 x = (() => { throw new Error('exception') })(); // 运行正确,never 类型可以赋值给 数字类型 y = (() => { throw new Error('exception') })(); // 返回值为 never 的函数可以是抛出异常的情况 function error(message: string): never { throw new Error(message); } // 返回值为 never 的函数可以是无限循环这种无法被执行到的终止点的情况 function loop(): never { while (true) { } }

五、类

1.类的写法

2.类的继承

3.属性修饰符(public、protected、private)

4.必传参数和可选参数

//类里面的修饰符:ts里定义属性的时候提供了三种修饰符:
/*
public:共有   在类里面、子类、类外面都可以访问
protected:保护类型   在类里面,子类里面可以访问,在类外部没法访问
private:私有     在类里面可以访问 ,类外面和子类都不访问
属性如果不加修饰符,默认是public
*/
class Person {
    name: string; //必传,属性修饰符这里没写就默认是public,同public name:string;
    private sex: string;
    protected age?: number; //age:可有可没有

    //namepro:必传,agepro:可传可不传,可选参数必须配置到 参数的最后面 //‘lisi’是namepro的默认值
    constructor(namepro: string = 'lisi', sexpro: string = '男', agepro?: number) {
        this.name = namepro;
        this.age = agepro;
        this.sex = sexpro;
    }
    run(): void {
        console.log(this.name);
    }
}
let zhangsan = new Person('zhangsan', '女');
zhangsan.run();
zhangsan.age;  //提示出错。age是保护类型

class Web extends Person {
    constructor(name: string) {
        super(name) //继承父级的参数需要同过super函数传值
    }
    work() {
        console.log(this.sex); //sex是父类的私有属性,所以子类是访问不到的,这里会提示错误

    }
}

5.参数中的三点运算符

//三点运算符,接受新参传过来的值
function sumFn(...result: number[]): number {
    let sum: number = 0;
    for (let i = 0; i < result.length; i++) {
        sum += result[i];
    }
    return sum;
}
sumFn(1, 2, 3, 4);
sumFn(1, 2, 3, 4, 5, 6)
//如果有默认的参数,那传参前面就是默认的参数,剩下的就在。。。的result中
function sumFn(a:number,b:number,...result: number[]): number {
    let sum: number = a+b;
    for (let i = 0; i < result.length; i++) {
        sum += result[i];
    }
    return sum;
}
sumFn(1, 2, 3, 4);
sumFn(1, 2, 3, 4, 5, 6)

六、ts函数重载

1.ts中的重载:通过为同一个函数提供多个函数类型定义来试下多种功能的目的

function getInfo(name: string): string;
function getInfo(age: number): string;
function getInfo(str: any): any {
    if (typeof str === 'string') {
        return '我叫' + str;
    } else {
        return '我的年龄' + str;
    }
}
getInfo('张三')  //我叫张三
getInfo(20)  //我的年龄20

七、类的静态属性 静态方法

1. /*es5中的写法*/ 
function
Person () {   // this.run = function () {} // 实例方法   // this.run = ()=> {} } Person.run = function () {} // 静态方法
2./*es6的写法*/
class Person1 {   name:string;   static sex = 'man'; // 静态属性   constructor(name: string) {     this.name = name;   }     eat() {     console.log(`${this.name}吃饭`)   }   static work() {   console.log(`这是一个静态方法` + Person1.sex)   // console.log(`${this.name}哈哈`) // 错误的写法,静态方法里面无法调用类的属性、方法。   } } var p = new Person1('aaa'); p.eat(); // 实例方法调用 Person1.work(); // 静态方法调用

八、ts中的抽象类和抽象方法,多态

1.typescript中的抽象类是提供其它类的基类,不能直接被实例化;

2.用abstract关键字定义的抽象方法和抽象类,不包括具体实现必须在派生类实现。

3. 抽象类: abstract 修饰, 里面可以没有抽象方法。但有抽象方法(abstract method)的类必须声明为抽象类(abstract class)

4.抽象类用于定义标准

5. 多态:父类定义一个方法不去实现,让继承它的子类去实现  每一个子类有不同的表现

abstract class Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    //抽象方法 ,不包含具体实现,要求子类中必须实现此方法
    abstract eat(): any;
    //非抽象方法,无需要求子类实现、重写
    run(): void {
        console.log('非抽象方法,不一定要子类实现、重写');
    }
}
//子类中必须实现父类抽象方法,否则ts编译报错
class Dog extends Animal {
    eat() {
        return this.name + '吃鱼'
    }
}
class Cat extends Animal {
    //子类中必须实现父类抽象方法,否则ts编译报错
    eat() {
        return this.name + "吃鱼";
    }
}
var dog = new Dog("tom");
var cat = new Cat("kitty");
console.log(dog.eat());
console.log(cat.eat());

//多态 ,一种事物的不同表现形态。如下面的代码中 先声明变量f是Animal类型,具体是Dog还是Cat,在new 对象时才知道
//如果是Dog,则f.eat()调用的是Dog类中的eat方法;如果是Cat,则f.eat()调用的是Cat类中的eat方法,这就是多态!!!
var f: Animal;//声明变量为Animal类型
//f=new Dog("sunny");
f = new Cat("sunny");
console.log(f.eat());

九、接口

1.接口:行为和动作的规范,对批量方法进行约束

2.接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面

3.分类:属性接口、函数类型接口、可索引接口、类类型接口

(1)属性接口:

//属性接口
interface fullName{
    firstName:string;
    secondName:string;
}
function getName(name:fullName):void{
    console.log(name.firstName + name.secondName); 
}
getName({
    firstName:'Li',
    secondName:'haha'
})
interface Shape {
    head: string;
    arm: string;
}
interface Human {
    name: string;
    age: number;
    shape: Shape;
    say(word: string): void;
}

let jack: Human = {
    name: 'Jack',
    age: 18,
    shape: {
        head: 'head',
        arm: 'arm'
    },
    say(word: string) {
        console.log(word)
    }
}
jack.say('hi')

(2)函数类型接口:

//函数类型接口
interface Fn{
    (key:string,val:string):string;
}
let add1:Fn = function(key:string,val:string):string{
    return key+val;
}
let add2:Fn = function(key:string,val:string){
    return `${key}------${val}`
}

(3)可索引接口(数组对象的约束,不常用)

//ts定义数组的方式
let arr1: number[] = [11, 22];
let arr2: Array<string> = ['11', '22'];
//可索引接口的实现
interface UserArr {
    [index: number]: string
}
let arr3: UserArr = ['aa', 'bb'] //ok
console.log(arr3[0]);
let arr4:UserArr=[11,'aa'];//报错

interface UserObj{
    [index:string]:string
}
let arr5:UserObj ={name:'张三'} //OK,但是这样实现已经不是数组,没有意义了,所以不常用

(4)类类型接口(对类的约束,和抽象类有点像)

interface Aniaml1 {
    name: string;
    eat(str: string): void;
}
//implements ,是对类Aniaml1的实现
class Dog1 implements Aniaml1 {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    eat(str: string) {
        console.log(this.name + '吃粮食' + str);

    }
}
let d = new Dog1('小黑');
d.eat('肉');

4.接口的拓展:接口可以继承接口

interface Animal {
    eat(): void;
}
interface Person extends Animal {
    work(): void;
}
class Web implements Person {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    eat() {
        console.log(this.name + '喜欢吃馒头');
    }
    work() {
        console.log(this.name + '写代码');
    }
}
let zhangsan = new Web('zhangsan');
zhangsan.work();

十、泛型

1.泛型的定义:指在定义函数、接口或者类的时候, 不预先指定其类型,而是在使用时手动指定其类型的一种特性

2.泛型分类:泛型函数、泛型类、泛型接口

(1)泛型函数

//使用泛型函数(T:类型变量)
function myfn<T>(args: T): T {
    return args;
}
let output = myfn<string>("Hello"); //明确传入类型参数
let output2 = myfn("Hello")  //不传入类型参数,TS根据上下文自动推断类型
//使用泛型变量(这可以让我们把泛型变量T当做类型的一部分使用,而不是整个类型)
function myfn1<T>(args: T[]): T[] {
    console.log(args.length)
    return args;
}
function myfn2<T>(args: Array<T>): Array<T> {
    console.log(args.length);
    return args;
}

(2)泛型类

class add<T>{
    value: T;
    add: (x: T, y: T) => T;
}
let myTest = new add<number>();
myTest.value = 0;
myTest.add = function (x, y) {
    return x + y
}

(3)泛型接口

//第一种方法
interface Test {
    <T>(args: T): T
}
let myTest: Test = function <T>(args: T): T {
    return args;
}
myTest<string>('20');
myTest<string>(20);

//第二种方法
interface Test1<T> {
    (args: T): T 
}
function myfn1<T>(args: T): T { 
    return args;
}
let myTest1: Test1<string> = myfn1;
myTest1('20') //ok
myTest1(20)//报错

(4)泛型约束(类型变量继承接口)

//例中,传入的参数必须具有length属性
interface Test{
    length:number;
}
function myfn<T extends Test>(args:T):T{
    console.log(args.length)
    return args;
}
myfn(3); //error
myfn("abc") //3

十一:模块

1.模块的概念

2.模块导出的几种方式:export导出声明、export导出语句、export default、import 导入模块

3.模块封装(DB库)

4.命名空间

十二、装饰器

1.概念

2.分类:属性装饰器、方法装饰器、方法参数装饰器、类装饰器(装饰器的执行顺序也是这样)

3.装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参)

(1)普通装饰器

//类装饰器
function logClass(target: any) {
    console.log(target); //httpClient类
    params.prototype.apiUrl = '动态扩展的属性';
    params.prototype.run = function () {
        console.log('动态拓展的方法');
    }
}

@logClass  
class httpClient {
    constructor() {

    }
    getData() {

    }
}
let http: any = new httpClient();
//类装饰器重载构造函数和当前类的方法(普通装饰器)
function logClass(target: any) { //target:httpClient 类
    return class extends target { //装饰器重载构造函数
        apiUrl: any = '我是修改后的数据';
        getData() {
            this.apiUrl + '----';
            console.log(this.apiUrl);
        }
    }

}

@logClass
class httpClient {
    public apiUrl: string | undefined;
    constructor() {
        this.apiUrl = '我是构造函数里面的apiUrl';
    }
    getData() {
        console.log(this.apiUrl);
    }
}
let http: any = new httpClient();
console.log(http.apiUrl);  //我是修改后的数据

(2)装饰器工厂(可传参)

     2.1   类装饰器

//类装饰器(装饰器工厂的方式)
function logClass(params: any) {  //params:传的参数

    return function (target: any) {//target:httpClient类
        console.log(params);//hello
        console.log(target);//httpClient类

        target.prototype.apiUrl = params; //可以用上传的参数
        target.prototype.run = function () {
            console.log('动态拓展的方法');
        }
    }
}

@logClass('hello')   //可以传参
class httpClient {
    constructor() {

    }
    getData() {

    }
}
let http: any = new httpClient();
console.log(http.apiUrl);  //hello

  2.2  属性装饰器

//属性装饰器
function logProperty(params: any) { //params:传的值:我是属性装饰器
    return function (target: any, attr: any) { //target:httpClient 类,attr:apiUrl
        target[attr] = params;
    }
}
class httpClient {
    @logProperty('我是属性装饰器')    //注意后面是不能加分号的
    public apiUrl: string | undefined;
    constructor() {
        this.apiUrl = '我是构造函数里面的apiUrl';
    }
    getData() {
        console.log(this.apiUrl);
    }
}
let http: any = new httpClient();
console.log(http.apiUrl);  //我是属性装饰器

2.3 方法装饰器//方法装饰器

function get(params: any) { //params:传的值:我是方法装饰器
    //target:httpClient类,methodName:方法名getData, desc:方法的描述
    return function (target: any, methodName: any, desc: any) {
        target.addPara = '我是拓展的属性';  //同类装饰器的方法
        target.addFn = function () {       //同类装饰器的方法 
            console.log('我是拓展的方法');
        }
        //修改装饰器的方法,把装饰器里面传入的参数改为string类型 
        //获取当前的方法 desc.value =getData() {console.log(this.apiUrl);}
        //先保存当前的方法
        let oldMethond = desc.value;
        //修改当前的方法
        desc.value = function (...args: any[]) {
            args = args.map((val) => {
                return String(val)
            })
            console.log(args);//['123','xxx'] 
       console.log(params); //我是方法装饰器
//将原来的方法继承到修改后的方法里面,这样既有修改的方法,又包含原有未修改的方法 oldMethond.apply(this, args) } } } class httpClient { public apiUrl: string | undefined; constructor() { this.apiUrl = '我是构造函数里面的apiUrl'; } @get('我是方法装饰器') getData(...args: any[]) { console.log(args); //['123','xxx'] console.log(this.apiUrl); //我是构造函数里面的apiUrl } } let http: any = new httpClient(); http.getData; //['123','xxx']
//我是方法装饰器
//['123','xxx'] //我是构造函数里面的apiUrl

2.4 方法参数装饰器

//方法参数装饰器:可以为类的原型增加一些元素数据(一般不用,类装饰器就可以做到这些)
function logParams(params: any) { //params:传的值:我是方法参数装饰器
    //target:httpClient类,methodName:方法名getData, paramsIndex:函数参数的index索引
    return function (target: any, methodName: any, paramsIndex: any) {
        target.addUrl = 'params';//可以为类的原型增加一些元素数据
    }
}
class httpClient {
    public apiUrl: string | undefined;
    constructor() {
    }
   
    getData( @logParams('我是方法参数装饰器') uuid:any) {
        console.log(uuid); //haha
    }
}
let http: any = new httpClient();
http.getData('haha');
原文地址:https://www.cnblogs.com/zhengyulu/p/12077981.html