TypeScript

1.TS概述

1.1 TS相比于js的优势:

优势一:类型化思维方式,提前发现错误,减少改bug时间;
优势二:提高代码可读性,并使维护和重构代码根据容易;
优势三:补充了接口,枚举等开发大型应用时js缺失的功能;

1.2.开发工具准备
1.2.1 安装解析ts工具包tsc(将ts转化成js)

image.png

安装: npm i -g typescript

1.3第一个ts文件
1.3.1执行代码,分两步:

1)ts -> js代码:tsc 文件名.ts

  1. 执行js:node 文件名.js;

解释:
ts转化js命令(tsc 文件名.ts):
新建tsdemo文件夹,新建hello.ts文件,在该文件目录下打开终端,输入tsc hello.ts,此时,文件夹就多出一个hello.js,即可生成同名的js代码

执行js命令(node 文件名.js):

image.png

1.3.2简化执行ts步骤

问题:每次修改代码后,都需要重复执行tsc 文件名.tsnode 文件名.js命令,太繁琐。
简化方式:使用ts-node包,直接在node.js中执行js代码(ts-node包内部已将ts->js),然后执行js代码

安装命令: npm i -g ts-node
执行命令:ts-node 文件名.ts

image.png

2 变量

2.1 什么是变量

两步:1.声明变量并指定类型 2.给变量赋值
如:第一步:let age: number = 18

2.2 ts中的数据类型

ts为了编码规范,增加了类型校验,提供以下数据类型:
布尔类型(boolearn);
数字类型(number);
字符串类型(string);
数组类型(array);
元组类型(tuple);
枚举类型(enum);
任意类型(any);
null和undefined;
void类型;
never类型
1).布尔类型

var flag:boolean = true;
flag = false;
console.log('flag:', flag); // false

2).数字类型

var num:number =123;
num = 234;
console.log('num:', num); // 234

3).string类型

var str:string ='hello';
str = 'hi';
console.log('str:', str); // hi

4).数组类型

// 三种方式
// 第一种:
var arr1:number[] = [11,111,111];
console.log(arr1); // [11,111,111]

// 第二种:
var arr2:Array = [11,22,33];
console.log(arr2); // [11,22,33]

//第三种:
var arr0:any[] = ['233433', 33, true];
console.log(arr0); // ['233433', 33, true]

5).元组类型(tuple):属于数组的一种,每一个位置指定一中类型

/**
 */
let arr3:[number,string] =[123, 'good'];
console.log('arr3:',arr3);

6).枚举类型:在状态程序中用自然语言中相应含义的单词来代表某一状态
enum 枚举名 {
标识符[=整数常数],
标识符[=整数常数],
...
标识符[=整数常数]
}

//如果标识符没有赋值,它的值就是下标
enum Color {red,green=4, 'orange'};
let thisColor_red:Color = Color.red;
let thisColor_green :Color=Color.green;
let thisColor_orange :Color=Color.orange;
// 如果标识符没有赋值,它的值就是下标
console.log(thisColor_red); // 0
// 赋值
console.log('thisColor_green:', thisColor_green); // 4
// 改变下标
console.log('thisColor_orange:', thisColor_orange); // 5

7).任意类型(any)

var num9: any = 123;
num9= 'str';
num9 = true;
console.log('num9:', num9); // true

//使用Object会报错,ts没有Object类型,可使用any
// var oBox:any =document.getElementById('box');
// oBox.style.color = 'red';

8).null 和 undefined其它类型的子类型

//可能是undefined,错误写法
var num11:number;
console.log(num11); //声明未赋值,会报错 输出:undefined

//可能是undefined,正确写法
var num12:undefined;
console.log(num12); //输出:undefined

//可能是null时
var num13 :null;
num13 = null;
console.log(num13); // null

//可能是null,可能是undefined时
var num15:number | null | undefined;
num15 = 1234;
console.log(num15); // 1234

9).void类型:表示方法没有返回任何类型

// 错误写法
// function run(): undefined {
//     console.log('run');
// }
// run();

//正确写法
function running(): void {
    console.log('123');  // 123
}
running();

10). never类型:是其他类型(包括null和undefined)的子类型,代表从不会出现的值
这意味着声明never的变量只能被never类型所赋值

// var a:never;
// a = (()=>{
//     throw new Error('错误');
// })();

3.函数

1).以前es5:函数声明

// 函数的定义
    function run() {
        return 'run1';
    }

    // 匿名函数
    var run2 = function() {
        return 'run2'
    }

2).ts函数声明

    function runTs():string {
        return 'run1';
    }
    // 匿名函数
    var run2Ts = function():string {
        return 'run2ts'
    }
    //函数调用
    run2Ts() //run2ts

3).ts中定义方法传参

function getInfo(name:string , age:number):string {
    return `${name}----${age}`;
}
getInfo('sum',11); // sum====11

var getInfoTs = function(name:string,age:number):string{
    return `${name}-${age}`;
}
getInfoTs('xiaozhang', 12); //xiaozhang 12

4).没有返回值

function run1():void {
    console.log('run');
}
run1(); //run

5).方法可选参数时,加 ?
es5里面方法的实参和形参可以不一样,但还是ts中必须一样,如果不一样就需要配置

function getInfoTss(name:string, age?:number) {
    return `${name}----${age}`;
}
getInfoTss('sum');// sum
// 注意:可选参数必须配置到参数的的后面

6).默认参数
es5里面没法设置默认参数,es6和ts都可以设置默认参数

function getA(name:string, age:number=20):string{
    if(age){
        return `${name}--${age}`;
    }else{
        return '${name}--haha';
    }
}
alert(getA('张三')); // 张三--20
alert(getA('李',30)) // 李--30

7).剩余参数 三点运算符

function sum1(a:number,b:number,...result:number[]):number{
    var sum = a + b;
    for(var i = 0; i < result.length;i++){
        sum+=result[i];
    }
    return sum;
}
console.log(sum1(1,2,3,4,5));//15
// 或者
function sum2(...result:number[]):number{
    var sum = 0;
    for(var i = 0; i < result.length;i++){
        sum += result[i];
    }
    return sum;
}
console.log(sum2(1,2,3,4,5,6)); //21

8).函数重载:
java中:重载指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况
ts中的重载:通过为同一个函数提供多个函数类型定义来实现多重功能的目的
ts为了兼容ES5以及es6重载的写法和java中有区别

function getReFn(name:string):string;
function getReFn(name:string,age:number):string;
function getReFn(name:string,age?:number):any{
    if(age){
        return '我叫:'+ name + '我的年龄是'+age;
    }else{
        return '我叫:'+name;
    }
}

alert(getReFn('zhangsan')); // zhangsan
// console.log(getReFn('san', 20)); //san 20
// console.log(getReFn(231333)); //错误写法

3.类

es5中的类

1)最简单的类

        function Person1() {
            this.name = 'lily';
            this.age = 34;
        }
        var p = new Person1;
        console.log(p.name);

2).构造函数和原型链里面增加方法

        //原型链上面的属性会被多个实例共享,构造函数不会
        function Person() {
            // 属性
            this.name = 'sam';
            this.age = 20;
            // 方法
            this.run = function () {
                console.log(this.name + '在运动');
            }
        }

        //原型链
        Person.prototype.sex = "男";
        Person.prototype.work = function () {
            console.log(this.name + '工作');
        }
        var p = new Person();
        p.work(); //sam工作

3).类的静态方法

        Person.getInfo = function () {
            console.log('静态方法');
        }
        Person.getInfo();

4).构造函数

        function Person3() {
            // 属性
            this.name = 'lucy';
            this.age = 20;
            // 方法
            this.run = function () {
                console.log(this.name + '在运动');
            }
        }

        Person3.prototype.sex = "女";
        Person3.prototype.work = function () {
            console.log(this.name + '逛街la');
        }
        //web类 继承Person类 原型链+对象冒充的组合继承模式
        function Web(){

        }
        //原型链实现继承,可以继承构造函数里面的属性和方法,也可以继承原型链上的属性和方法
        Web.prototype=new Person3();
        var w =new Web();
        w.work() //lucy逛街la
        w.run() //lucy在运动

5)传参时:构造函数和原型链实例化子类的时候没法给父类传参,用call或者 Web.prototype= Person.prototype;

function Web4(name,age){
            Person.call(this.name,age);
        }
         //或者原型链
        Web4.prototype= Person.prototype;
3.2ts类

1).类的定义

class Person{
    name:string;
    constructor(name:string){
        this.name=name;
    }
    getName():string{
        return this.name;
    }
    setName(name:string):void{
        this.name=name;
    }
}
var p=new Person('sam');
console.log(p.getName()); // sam
p.setName('lili')
console.log(p.getName()); //lili

2).ts中实现继承

class Animal {
    move(distanceInMeters: number = 0) {
        console.log(`Animal moved ${distanceInMeters}m.`);
    }
}

class Dog extends Animal {
    bark() {
        console.log('Woof! Woof!');
    }
}

const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();

3)类作为接口使用

class Point {
    x: number;
    y: number;
}

interface Point3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};

4.枚举

存在一种特殊的非计算的常量枚举成员的子集:字面量枚举成员。 字面量枚举成员是指不带有初始值的常量枚举成员,或者是值被初始化为

任何字符串字面量(例如: "foo", "bar", "baz")
任何数字字面量(例如: 1, 100)
应用了一元 -符号的数字字面量(例如: -1, -100)

enum ShapeKind {
    Circle,
    Square,
}

interface Circle {
    kind: ShapeKind.Circle;
    radius: number;
}

interface Square {
    kind: ShapeKind.Square;
    sideLength: number;
}

let c: Circle = {
    kind: ShapeKind.Square,
    //    ~~~~~~~~~~~~~~~~ Error!
    radius: 100,
}

5.类型兼容性

函数参数双向协变
当比较函数参数类型时,只有当源函数参数能够赋值给目标函数或者反过来时才能赋值成功。 这是不稳定的,因为调用者可能传入了一个具有更精确类型信息的函数,但是调用这个传入的函数的时候却使用了不是那么精确的类型信息。 实际上,这极少会发生错误,并且能够实现很多JavaScript里的常见模式。例如

enum EventType { Mouse, Keyboard }

interface Event { timestamp: number; }
interface MouseEvent extends Event { x: number; y: number }
interface KeyEvent extends Event { keyCode: number }

function listenEvent(eventType: EventType, handler: (n: Event) => void) {
}

listenEvent(EventType.Mouse, (e: MouseEvent) => console.log(e.x + ',' + e.y));


listenEvent(EventType.Mouse, (e: Event) => console.log((e).x + ',' + (e).y));
listenEvent(EventType.Mouse, <(e: Event) => void>((e: MouseEvent) => console.log(e.x + ',' + e.y)));

listenEvent(EventType.Mouse, (e: number) => console.log(e));

6.迭代器和生成器

for..of和for..in均可迭代一个列表;但是用于迭代的值却不同,for..in迭代的是对象的 键 的列表,而for..of则迭代对象的键对应的值

let list = [4, 5, 6];

for (let i in list) {
    console.log(i); // "0", "1", "2",
}

for (let i of list) {
    console.log(i); // "4", "5", "6"
}

另一个区别是for..in可以操作任何对象;它提供了查看对象属性的一种方法。 但是 for..of关注于迭代对象的值。内置对象Map和Set已经实现了Symbol.iterator方法,让我们可以访问它们保存的值。

let pets = new Set(["Cat", "Dog", "Hamster"]);
pets["species"] = "mammals";

for (let pet in pets) {
    console.log(pet); // "species"
}

for (let pet of pets) {
    console.log(pet); // "Cat", "Dog", "Hamster"

7.Symbol

symbol类型的值是通过Symbol构造函数创建的,是不可改变且唯一的,也可以被用做对象属性的键,也可以与计算出的属性名声明相结合来声明对象的属性和类成员,

const getClassNameSymbol = Symbol();

class C {
    [getClassNameSymbol](){
       return "C";
    }
}

let c = new C();
let className = c[getClassNameSymbol](); // "C"

你可能感兴趣的:(TypeScript)