TypeScript从入门到精通

446 阅读6分钟

NPM 安装 TypeScript

npm install -g typescript

查看版本号

tsc -v

在vscode中配置ts自动生成js文件

  1. 在项目根目录 tsc --init
  2. 改 生成的 tsconfig.json "outDir": "./js" (可以配置生成项目的路径)
  3. 任务 -- 运行任务 -- 监视 tsconfig.json

ts 为了使编写的代码更规范,更有利于维护,增加了类型校验

写 ts 代码必须指定数据类型

基本数据类型

Boolean

var flag:boolean = true;
flag = false;

Number

var num:number = 123;
num = 456;

String

var str:string = 'str';

Array

demo1

在数字类型后面加 []

var arr:number[] = [1,2,3,4,5]; // 正确写法
var arr:number[] = ['a',1,2]; // 错误写法
demo2

使用数组泛型

var 数组名:Array<数组值类型> = [xx,xx,xx]

var arr:Array<number> = [1,2,3,4];

var arr:Array<string> = ['1','2','3','4'];
demo3

借助于 any 数据类型

var arr3:any[] = ['1',2,'test'];
demo4

元组类型 ==》tuple类型 属于数组的一种

var tup:[number,string] = [123,'this is tuple']; // 正确写法
var tup:[number,string] = [123,2,'this is tuple']; // 错误写法

元组类型 tuple

用来表示已知元素数量和类型的数组,各元素的类型不需要相同,对应位置的类型需要相同

let x: [string, number];
x = ['Runoob', 1];    // 运行正常
x = [1, 'Runoob'];    // 报错
console.log(x[0]);    // 输出 Runoob

枚举类型 enum

枚举类型用于定义数值集合

enum 枚举名 {
	 标识符[=整型常数],
     标识符[=整型常数],
 	   ....        
 	}
enum Color {Red, Green, Blue};
let c: Color = Color.Blue;
console.log(c);    // 输出 2
enum res {
    success = 1,
    error = 0
}

let res_flag:res = res.success;
console.log('枚举类型',res_flag); // 1

注意:如果标识符没有赋值,那么它的值就是该标识符的下标(没有赋值,会在前一个值的基础上递增)

any 任意数据类型

任意值是 TypeScript 针对编程时类型不明确的变量使用的一种数据类型,它常用于以下三种情况

var an_str:any = 'Test any type';
an_str = '0123';

Null 和 Undefined

null

在JS中 null 表示 “什么都没有”。

null 是一个只有一个值的特殊类型。表示一个空对象引用。

用 typeof 检测 null 返回的是 object

undefined

// 一个元素定义多个数据类型
var doc:number | undefined | null;
doc = 123;

void类型

typescript中的void表示没有任何数据类型,一般用于定义方法的时候没有返回值

function testVoid():void {
    console.log('void类型');
}
// 函数有返回值,并且返回值是 数值类型
function testNum():number { 
    let num:number = 123;
    return num;
}

函数的定义方式

函数声明法
function testFun():number {
    let test_num:number = 123;
    return test_num;
}
匿名函数法
let test_num2 = function():string {
    let test_str:string = 'Test function';
    return test_str;
}
console.log('111',test_num2());
函数传参
function testParams(name:string,age:number):string {
    return `${name}-----${age}`;
}
console.log('函数传参',testParams('张三',20));
可选参数

注意:可选参数必须配置到参数的最后面

function chooseParams(name:string,age?:number):string {
    return `${name}-----${age}`;
}
console.log('可选参数',chooseParams('zs'));
默认参数
function defaultParams(name:string,age:number=30):string {
    return `${name}-----${age}`;
}
console.log('默认参数',defaultParams('zs'));
剩余参数

使用es6拓展运算符是为了保证参数个数不确定的情况

function surplusParams(a:number,...arr:number[]):number {
    let sum = a;
    for (var i = 0;i<arr.length;i++) {
        sum += arr[i];        
    }
    return sum;
}
console.log('剩余参数',surplusParams(10,1,2,3,4));

函数重载

定义:

函数名相同,参数个数,参数类型,参数顺序不同

意义:

传入不同的参数,得到不同的结果


function add (arg1: string, arg2: string): string
function add (arg1: number, arg2: number): number

// 需要使用 | 或 ? 操作符,把所有可能的输入类型全部包含进去 

function add(arg1:string | number,arg2:string | number) {
    if(typeof arg1 === 'string' && typeof arg2 === 'string') {
        return arg1 + arg2;
    } else if(typeof arg1 === 'number' && typeof arg2 === 'number') {
        return arg1 + arg2;
    }
}
alert(add('Hello','World'))

TS中定义类

class Person {
    public name:string; // 属性

    constructor(n:string) { // 实例化类的时候会触发
        this.name = n;
    }
    run():void {
        alert(this.name);
    }
}

var p = new Person('张三');
p.run();

属性修饰符

/**
 * public: 公有的,      在类内部,子类,类外面都可以访问
 * protected: 保护类型   在类内部,子类 可以访问
 * private:私有         在类内部,可以访问
 * 
 * 属性如果不加任何修饰符,默认是 public
 */

继承

通过 extends 和 super 实现

class Student extends Person {
    constructor(name:string) {
        super(name); // super 在此处,就相当于 父类中的 constructor
     }
}
var s = new Student('李四');
s.run();

多态

父类定义一个方法不去实现,让继承它的子类去实现,每一个子类都有不同的实现方式

class Anil {
    name:string;
    constructor(name:string) {
        this.name = name;
    }
    eat() { // 具体怎么吃 父类 不去实现,让继承它的子类去实现,每个子类的实现方式都不同
        console.log('吃的方法');
    }
}
class Cat extends Anil {
    constructor(name:string){
        super(name);
    }
    eat() {
        alert(`${this.name} 吃肉`);
    }
}
var c = new Cat('小猫');
c.eat();
class Dog extends Anil {
    constructor(name:string){
        super(name);
    }
    eat() {
        alert(`${this.name} 吃骨头`);
    }
}

抽象类

抽象类用于提供其它类继承的基类,不能直接被实例化

使用 abstract 关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体的实现,必须 在派生类 中实现

主要作用:

抽象类和抽象方法主要是用来定义标准的,例如:Animation 这个类要求它的子类必须包含 eat 方法

abstract class Animaltion {
    name:string;
    constructor(name:string) {
        this.name = name;
    }
    abstract eat():any; // 抽象方法
    
    run() {
        alert('抽象类中也可以有普通的方法');
    }
}
/**
 * 注意:抽象类的子类,必须实现抽象类中的抽象方法
 */

class Cat extends Animaltion {
    constructor(name:string) {
        super(name);
    }
    eat() {
        alert(`${this.name}吃小鱼`);
    }
} 
var  c = new Cat('小花猫');
c.eat();
c.run();

继承,多态,抽象类总结

相同点:

多态和抽象类 都是属于继承的一种

多态和抽象类不同点:

  • 抽象类使用 abstract 关键字定义,多态不使用

  • 抽象方法不包含具体的实现,没有方法体,而多态中的方法有方法体

    • eat() { // 具体怎么吃 父类 不去实现,让继承它的子类去实现,每个子类的实现方式都不同
           console.log('吃的方法');
      }
      abstract eat():any; // 抽象方法
      
  • 抽象类中的抽象方法其子类必须去实现, 而 多态中的方法其子类可以去实现,也可以不去实现

  • 抽象类中有 抽象方法 和普通方法,普通类中只能有 普通方法 ,不能有 抽象方法

接口

接口的作用

用于定义标准

在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范

在程序设计里面,接口起到一种限制和规范的作用。

接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里面方法的实现细节,它只规定这批类必须提供某些方法,提供这些方法的类,就可以满足实际需要。

ts中的接口类似于java,同时还增加了更加灵活的接口类型,它包括属性,函数,可索引和类等

属性类接口

 interface FullName {
     name:string;
     age:number;
     gender?:string; // 可选参数
 }
 function getInfo(info:FullName) {
    console.log(`姓名:${info.name} -- 年龄:${info.age} -- 性别:${info.gender}`);
 }

 function showInfo(show:FullName) {
    console.log(`姓名:${show.name} -- 年龄:${show.age} -- 性别:${show.gender}`);    
 }
     
 /**
  * 这种传递参数的方式:必须和接口中定义的参数保持一致,接口中未定义的参数,不能传递
  */
 getInfo({
     age:20,
     name:'张三',
     gender:'男'
 })

 showInfo({
     name:'李四',
     age:18
 })

 /**
  * 这种传递参数的方式,只要对象中的参数 包含 接口中定义的参数就可以
  */
 let obj = {
     name:'张三',
     age:20,
     gender:'男',
     hobby:'吃'   
 }
//  getInfo(obj);

函数类型的接口

传入的参数,以及返回值进行约束

// 模拟加密的函数类型接口
interface encrypt {
    (key:string,value:string):string;
}

/**
 * md5:encrypt 这句化的意思是:md5引用 encrypt 这个函数
 */

/**
 * 注意:function(key:string,value:string):string
 *     函数的参数名可以是其它的 function(a:string,b:string)
 *     但是参数名的数据类型,必须相同,且函数的返回类型也必须一致  
 */ 
var md5:encrypt = function(key:string,value:string):string {
    return key + value;
}

console.log(md5('aaa','bbb'));

可索引接口

主要用于对 数组 和 对象 进行处理 (不常用)

interface userInfo{
    [index:number]:string; // [index:索引的类型]:数组中每一项类型的限制,当索引的类型为 number=》是数组,是string =》对象
}
/**
 * 索引的数据类型为 number类型,数组中的每一项 为 string类型
 */ 
var arrInfo1:userInfo = ['1','2','3'];

interface objInfo{
    [index:string]:number;
}
/**
 * 索引的数据类型为 string,每一项的值为 number类型
 */
var objInfo1:objInfo = {name:1,age:2};

类类型接口

对类的约束,和抽象类类似

通过 interface,implements 关键字来实现

interface Anim{
    name:string;
    eat(str:string):void;
}
/**
*  一个类如果要实现某一接口,必须要与接口中的属性和方法一致
*/
class Catd implements Anim {
    name:string;
    constructor(name:string) {
        this.name = name;
    }
    eat() {
        console.log(`${this.name}吃肉`);
    }
}
var catd = new Catd('小猫');
catd.eat();

可扩展接口

接口可以继承接口

interface Anim{
    name:string;
    eat(str:number):void;
}

interface Animations extends Anim {
    work():void;
}

class Catd {
    age:number;
    constructor(age:number) {
        this.age = age;
    }
    code() {
        console.log(`写代码`);
    }
}


class Progrems extends Catd implements Animations {
    gender:number; // Progrems 私有的 gender 属性
    name:string; // 实现接口 Anim 的name属性
    constructor(gender:number,name:string) {
        super(gender);        
        this.gender = gender;
        this.name = name;
    }
    work() { // 实现接口 Animations 的方法
        console.log(`work方法---${this.name}---gender${this.gender}`);
    }
    eat() { // 实现接口 Anim 的方法
        console.log('eat方法');
    }
}

var progrems = new Progrems(1,'张三');
progrems.work();

泛型

在软件工程中,我们不仅要创建一致的,定义良好的API,同时也要考虑可重用性。

组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型。这在创建大型系统时为你提供十分灵活的功能

在像 Java或 c#这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。这样用户就可以以自己的数据类型来使用组件

简单理解

泛型就是解决 类 接口 方法的复用性,以及对不特定数据类型的支持

更新中。。。。。