入门typeScript

2020-03-09  本文已影响0人  who_are_you_

typeScript在vue中如何使用。

一、了解typeScript的基本类型及声明变量的几种方法的对比。

1、private、public、protected修饰符对比

概念:
跟java类似,TypeScript的访问修饰符有三个,分别是public、private、protected 。

TypeScript的默认访问修饰符是public。

1)public声明的属性和方法在类的内部和外部均能访问到。

2)protected声明的方法和属性只能在类的内部和其子类能访问。

例:

class Animal {
  protected name: string;

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

class Rhino extends Animal {
     constructor() {
          super('Rhino');
    }         
    getName() {
        console.log(this.name) //此处的name就是Animal类中的name
    }
}

3)private声明的方法和属性只能在其类的内部访问。

例:

class Animal {
  private name: string;

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

let a = new Animal('Cat').name; //错误,‘name’是私有的

2、类的继承

typescript中类的继承用到的是:extends和super

class Demo{
    //类的属性
    name:string;
    age:number;
    //类的构造函数
    constructor(name:string,age:number){
        this.name=name;
        this.age=age;
    }
    //类的方法
    run():string{
        return `${this.name}的年龄是${this.age}岁`
    }
}
// Web继承Demo

class Web extends Demo{
    constructor(name:string, age: number){
        super(name, age);//相当于初始化父类的构造函数
    }
}

var w=new Web("李四", 1);

3、typeScript基本的类型

Javascript 的类型分为两种:原始数据类型和对象类型,TypeScript 支持与JavaScript几乎相同的数据类型,此外还提供了枚举、元组等实用的类型。基本数据类型包括:数值、字符串、布尔值、null、undefine、void 以及 ES6 新增的 symbol。

(1)数值类型

let decNum : number = 12
let drNum : number = NaN
let infinityNum : number = Infinity
// ES6 中的二进制表示法(0b 或者 0B 开头)
let binaryLiteral: number = 0b1010;
// ES6 中的八进制表示法(0o 或者 0O 开头)
let octalLiteral: number = 0o744;

(2)字符串类型

// 普通字符串
let myName : string = 'song jun bo'
// 模板字符串
let sentence : string = `This is my name${myName}`

(3)boolean类型

let isDone: boolean = false;

(4)null和undefined类型

在 Typescript 中 使用 null 和 undefined 来定义这两个数据类型。

let n : null = null
let un : undefined = undefined

(5)viod空类型

空类型顾名思义表示没有任何类型,常见于函数中,当函数不需要返回值时可以指定返回值为空类型。

function warnUser(): void {
   // 一些逻辑代码,不需要返回值,则需要返回void值
}

(6)symbol类型

// 定义一个symbol变量

let sym : symbol

// 调用Symbol 构造函数,创建变量

let sy1 : symbol = Symbol()
let sy2 : symbol = Symbol()
console.log(sy1 === sy1) // false

// 构造函数可传入如参数,symbol 是不可变且唯一的,即使Symbol 构造函数传入的key值一样

let sy3 : symbol = Symbol('same')
let sy4 : symbol = Symbol('same')
console.log(sy3 === sy4) // false

// symbol 可以和字符串一样作为对象的 key,由于symbol 唯一,因此,作为对象属性的key可避免对象属性覆盖问题

let symKey = Symbol();
let obj = {
    [symKey]: "value"
};
console.log(obj[sym]); // "value"

(7)任意类型any

有时候,在编程阶段,我们并不知道或者并不想为一个变量指定一个类型,因为有可能这个这个变量来自第三方库,或者来自用户输入。这个时候可以使用any 任意类型,任意类型变量可避开typescript 类型检查器的检查。
下面的例子定义了任意类型的变量myFavoriteNumber,这个变量既可以被赋值为string 类型的值也可以被赋值为 number类型的值。

let myFavoriteNumber: any = 'seven';
myFavoriteNumber = 7;

值得注意的是,任意值的属性和方法,在任意值上访问任何属性和方法都是可以的。比如定义任意类型变量 anything,并调用setName 方法,虽然anyThing 上没有setName 函数,但ts类型检查的时候不会报错,运行阶段才会报错,这个侧面说明静态类型语言的好处,将报错扼杀在摇篮之内。

let anyThing : any = 'string';
anyThing.setName('name');

另外一点需要特别注意,声明一个any 类型的变量之后,对它的任何操作,返回的内容的类型都是任意值,如果声明变量的时候未指定其类型,会被默认推断为任意类型,如:

let someThing;
someThing = 'string'
someThing = 100
// 等同于

let someThing:any 
someThing = 'string'
someThing = 1000

(8)元组类型

元组类似数组,只不过元组可以指定元组中各个元素的类型,并且各元素的类型不必相同,如:

let tuple : [String,Number] = ['tupleName',123]

// 和数组一样,元组可用角标取值,如:

console.log(tuple[0]) // tupleName
console.log(tuple[1]) // 123

// 同样的,元组可以通过角标为元组变量赋值

tuple[0] = 'tupleName2'
tuple[1] = 456
// 注意,当赋值给越界的元组时,它的类型会被限制为元组中每个类型的联合类型

tuple[2] = 'www.baidu.com' // 可行,因为该元组的联合类型为 string | number
tuple[2] = false //报错,因为该元组的联合类型为 string | number
// 注意:当直接为元组变量初始化或者赋值时,需提供元组类型中所有指定的项

let tuple2 : [String,Number]
tuple2 = ['tuple2'] //会报错
tuple2[0] = 'tuple2' // 会报错
let tuple2 : [String,Number] = ['tuple2',124]

(9)类型推断

如果定义的变量没有为他明确指明一个类型,Typescript 会依照类型推论的规则推断出一个类型。

let myType = 'string'  
//这里实际上等价于 
let myType : string = 'string' 
myType = 44 // 报错,因为此时,myType 变量被推断为 string 类型,不能再被赋值为number类型

注意:如果声明一个变量的时候没有明确指定类型且没有赋值,那么不管之后有没有赋值都会被推断为任意类型而完全不会被类型检查。

let myType // 此时相当于 let myType:any
myType = 'myType'
myType = 100

(10)联合类型

联合的类型的作用是可以为变量定义多个类型,多种类型之间用 “ | ” 分格

let myTypeUnion : string | number 
myTypeUnion = 'string'
myTypeUnion = 100
myTypeUnion = false // 报错,因为 联合类型中并没有 boolean 类型

注意:Typescript 不确定联合类型的变量究竟是哪个类型的时候 ,只能访问此联合类型所有类型共有的属性和方法

function getMyTypeUnion(myParam:string|number){
    // return myName.length // 报错,因为length不是 string 类型和number 类型共有的属性
    return myParam.toString() //正常,因为 toString() 是共有的函数,
}

另外一个例子,结合接口概念:

interface Bird {
    fly();
    layEggs();
}

interface Fish {
    swim();
    layEggs();
}

function getSmallPet(): Fish | Bird {
    let fish = {
        swim(){

        },
        layEggs(){

        }
    }
    return fish
}

let pet = getSmallPet();
pet.layEggs(); // 正常,因为 layEggs 方法是接口 Fish 和 Bird 共有的
pet.swim();    // 报错,因为swim方法不是 接口 Fish 和 Bird 共有的

(11)类型断言

类型断言允许自己断定某个变量的类型。
语法:
<类型>值
或者
值 as 类型
联合类型说到,联合类型只能访问共有的属性和方法,引用非共有的属性或者方法类型检查机制是不允许的,当然你可以像在 Javascript 中那样通过 if else 判断来区分不同类型然后调各自类型的属性和方法,如:

function getMyTypeUnionAsert(myParam:string|number){
    // return myName.length // 报错因为,length不是 string 类型和number 类型共有的属性
    // return myParam.toString() //不报错,因为 toString() 是共有的函数,
    if( typeof(myParam)=='string' ){
        return myParam.length
    }
    if( typeof(myParam)=='number' ){
        return myParam.toFixed(2)
    }
}
let resultAsert = getMyTypeUnionAsert('string') // resultAsert 值为 6
let resultAsert2 = getMyTypeUnionAsert(100.1234) // resultAsert2 值为 100.12

但有时候你十分确定传入函数的变量的类型就是 string 或者 number,因此你并不想写 if else 来判断变量类型,这个时候可以使用类型断言,如:

function getMyTypeUnionAsertYes(myParam:string|number){
    let newP = <string>myParam
    return newP.length
}
// 或者
function getMyTypeUnionAsertYes(myParam:string|number){
    let newP = (myParam as string).length
    return (myParam as number).toFixed()
}

(12)类型别名

类型别名就是为类型取另外一个名字,使用 type 关键字来标示。
类型别名常见于联合类型,因为,联合类型有点长,你懂的,比如下面这个联合类型

let unonType :string | number | boolean | object | (() => string)
// 类型别名这样定义:

type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
    if (typeof n === 'string') {
        return n;
    }
    else {
        return n();
    }
}

类型别名有时候可接口看起来有点像,比如:
这样定义了一个叫 aliasObj 类型别名

type aliasObj = {
    name:string,
    age:number,
    getName:(age:number)=>{}
}
// 这样定义了一个叫 interObj 接口

interface interObj {
    name:string,
    age:number,
    getName:(age:number)=>{}
}
// 类型别名和接口同样都可以使用泛型(泛型后面的文章会详细讲解),如:

type tree<T> = {
    value:T,
    key:T,
    other:number | string 
}

interface car<T> {
    wheel:T,
    speed:T,
}
// 当然,类型别名和接口有区别,接口可以被 extends 和 implements ,类型别名不行

interface bus extends car<number>{
}
// 这样会报错:
type otherTree extends tree{
} 

(13)枚举类型

枚举类型用来将取值限定在一定的范围之内,比如一周七天限定周一到周日分别用0至6的数字表示
1、枚举中若未明确赋值,枚举默认从0递增
可通过点语法或者键值对的方式取值

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days.Tue === 2); // true
console.log(Days.Fri === 6); // true

2、明确赋值时,从赋值位置递增

enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};
console.log(Days.Sun) // 7
console.log(Days.Mon) // 1
console.log(Days.Sat) // 6

一个使用枚举的例子,通过枚举的属性来访问枚举成员,和枚举的名字来访问枚举类型

enum Response {
    No = 0,
    Yes = 1,
}
function respond(recipient: string, message: Response): void {
    // ...
}
respond("Princess Caroline", Response.Yes)

3、字符串枚举
需要注意,在一个字符串枚举中,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。

enum Direction {
    Up = "UP",
    Down = "DOWN",
    Left = "LEFT",
    Right = "RIGHT",
}

4、手动赋值的枚举项也可以为小数或负数,此时后续未手动赋值的项的递增步长仍为 1

enum Days {Sun = 7, Mon = 1.5, Tue, Wed, Thu, Fri, Sat};
console.log(Days["Sun"] === 7); // true
console.log(Days["Mon"] === 1.5); // true
console.log(Days["Tue"] === 2.5); // true
console.log(Days["Sat"] === 6.5); // true

5、枚举的计算所得项
枚举值可由计算所得

enum Color {Red, Green=1+2, Blue = "blue".length};

6、常量枚举
常量枚举 用 const 标示

const enum Directions {
    Up,
    Down,
    Left,
    Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];

(14)数组类型

数组类型的定义方式有多种方式
1、最简单的一种,类型+放括号,如:

let numArr : number[] = [1,2,3] // numArr 数组内不能放其他类型的数据,比如字符串或者布尔值
let objArr : Object[] = [ {}, function(){}, (p:string)=>{} ]
// any 类型数组
let anyArr : any[] = [ 1,'string', function(){}, false ]

2、使用数组泛型定义数组类型

let nArr : Array<number>
nArr = [1,100,58]
let aArr :Array<any>

3、用接口来描述数组

interface NumberArray {
    [index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];

二、函数

(1)Typescript 中定义函数可同时定义函数接收的参数类型和函数的返回值类型

function myFuncTs (x:number,y:number):number {
    return x+y
}
let result = myFuncTs(12,13)

当函数的返回值类型没有指定时,typescript 会自动根据函数返回值推断返回类型

可以使用接口来定义一个函数需要符合的形状,如:

interface addFuncInteface{
    (x:number,y:number):number
}
let addF : addFuncInteface = (left:number,right:number)=>{ return left + right }

(2)可选参数
JavaScript里,函数的每个参数都是可选的,可传可不传。 没传参的时候,它的值就是undefined。在Typescript 中可以用 ? 定义函数的可选参数,需要注意的是,可选参数必须在必须参数之后,否则报错。
下面的例子中,name 参数是可选参数,可传可不传。

interface callbackInterface{
    (result:any):void
}
function canChoiceParames(width:number,height:number,callback:callbackInterface,name?:string):object {
    let tempObj = {
        w:width,
        h:height,
    }
    callback(tempObj)
    return tempObj
}
 let res = canChoiceParames(100,200,function(res){
    
},'myName')

(3)默认参数
与可选参数不同的是,带默认值的参数不需要放在必须参数的后面
下面的例子中 height 参数默认100

function defaultParams(width:number,height:number = 100){
}

(4)剩余参数
必要参数和默认参数有一个共同点:他们都只表示某一个参数。但是有时候会有同时操作多个参数的需求,或者你并不知道会有多少个参数会传进来。在JavaScript里,你可以使用 arguments来访问所有传入的参数。在Typescript 中可以把所有参数、或者某部分参数收集到一个变量里。注意剩余参数只能是最后一个参数。

function buildName(firstName: string, ...restOfName: string[]) {
  return firstName + " " + restOfName.join(" ");
}

let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

上面的例子中restOfName参数为一个包含了剩余参数的数组,该数组为["Samuel", "Lucas", "MacKinzie"]
(5)函数重载
当函数入参使用联合类型同时返回值也有有多种类型时,函数重载允许对函数接受不同参数的数量和类型时作出不同的处理。
比如实现一个反转函数,输入为数字类型123时输出321,输入字符串类型 abc 时输出 cba
利用联合类型,该需求实现如下

function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }else{
        return x
    }
}

这样虽然能实现需求,但是函数参数与返回值的说明不够直观。调用者容易迷惑,当传入函数的参数类型为number 时返回值的类型究竟是 number 还是string。
函数重载可以解答这样的疑惑,使函数的类型定义表达更加直观。

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }else {
        return x
    }
}

前面两个reverse 是函数声明,最后一个reverse 是函数实现,有参数类型和返回值类型随意搭配的意思。前面两个 reverse 对函数进行了声明,第一个reverse声明的内容为,当传入函数的参数类型为number 时,函数返回值类型为number 类型;第二个 reverse 声明的内容为,当传入函数的参数类型为string 时,函数返回值类型为string。
下面是另一个例子,动手试一下吧。
同样的,前面几个testOverload为函数声明,最后一个testOverload为函数实现:

function testOverload(x:string,y:boolean):number;
function testOverload(x:string,y:number):string;
function testOverload(x:number,y:number):string;
function testOverload(x:number,y:boolean):number;
function testOverload(x:string | number, y:number|boolean) :string | number  {
    return x
}
let o1 = testOverload('string',false); // 此时 o1 类型为numer,鼠标移动到 o1 变量上可看到类型
let o2 = testOverload('string',10);// 此时 o2 类型为string,鼠标移动到 o2 变量上可看到类型
let o3 = testOverload(12,10);// 此时 o2 类型为string,鼠标移动到 o2 变量上可看到类型
let o4 = testOverload(13,true);// 此时 o2 number,鼠标移动到 o2 变量上可看到类型

补充

上一篇下一篇

猜你喜欢

热点阅读