初学TypeScript

151 阅读5分钟

为什么要学习typescript?

对JavaScript的增强

  • 可以提供类型标注 大大的增强的代码的可读性与可维护性
  • 提供不断发展的JavaScript特性 可以让我们编写出更加健壮的代码

未来前端发展的趋势

在未来前端应用会越来越复杂,ts是特别适合开发大型复杂项目的。现在几大前端主流框架对TS的兼容性越来越好 , Vue3 React Angular

技术转型的优势

现在很多公司招聘要求上会写着要求掌握一门或者多门前端语言,JS肯定是基础,如果你也会TS的话,现在来说,这个肯定是优势,未来TS绝对是趋势

提升个人能力与竞争力

因为JS是弱类型动态语言,大型项目中使用JS最后会遇到各种各样的问题,掌握了TS开发技巧的话,对于个人成长是非常好的

TypeScript快速入门

先来看两段代码

const hello = (a,b) => a + b     //JS代码
const hello = (a:number,b:number):number => a+b//TS代码

可以看到,这两个函数的功能都是一样的,实现一个相加的函数。理想情况下,我们调用hello(1,2)能得到我们想要的结果,但是万一我们参数输入错误了呢???????比如hello(1,'ere'),JS写的代码在这种情况下依然能得到结果,是一个字符串,但这个是我们想要的结果吗???nonono , TS写的代码在这种情况下就会报错,这就体现出了TS的优势了,你参数定义的什么类型,传进去的参数就应该是什么类型

Object 类型

所有非原始类型的数据类型都是,Object类型

let foo : object = function(){}
let foo1 : object = []
let foo2 : object = {}
//——————————————————————
let foo : {foo : number} = {foo:23} //这种直接赋值的方法格式是:声明了多少变量,那么就应该实例化多少个对象
let foo1 : {foo : number} = {foo:23,age:'2324'} //这个就会报错

TypeScript数据类型之基础类型

数字,字符串,布尔值
let bool:boolean = false//true
let number:number = 2021
let number1:number = 0b10101//支持二进制
let number2:number = 0x744//支持八进制
let number3:number = 0xf00d//支持16进制
let str:string = 'zhoujing'
数组

TypeScript像JavaScript一样可以操作数组元素。 有两种方式可以定义数组。 第一种,可以在元素类型后面接上 [],表示由此类型元素组成的一个数组

let arr1 : Array<number> = [1,2,3]//数组泛型
let arr2 : number[] = [1,2,3]
元组 Tuple

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为 stringnumber类型的元组。

let tuple:[string,number,boolean];
tuple = ['zhoujing',25,true] //ok
tuple = [25,'zhoujing','haha'] //incorrect
枚举 enum

enum类型是对JavaScript标准数据类型的一个补充。 像C#等其它语言一样,使用枚举类型可以为一组数值赋予友好的名字。

官方文档入口

enum Slolar{
  sun = 0,
  earth,
  moon,
  triton
}
enum Solar{
  sun ,
  earth,
  moon,
  triton
}

使用枚举很简单:通过枚举的属性来访问枚举成员,和枚举的名字来访问枚举类型 , 我们接触到比较多的可能是数字枚举,sun值为1,后面的值没有赋值的话,就会依次自增长 , 如果没有初始值,枚举对象的第一个值就会赋值为0

null与undefined

TypeScript里,undefinednull两者各自有自己的类型分别叫做undefinednull。 和 void相似,它们的本身的类型用处不是很大

官方文档入口

let u: undefined = undefined;
let n: null = null;

官方文档是鼓励使用-- strictNullChecks,这个是在tsconfig.json文件里面

接口 interface

接口就是用来约束对象的条件,只起一个约束的作用,实际运行中并没有实际意义,在这里同时引入可选成员,只读成员,动态成员

interface inter{
    name : string 
    inner?:string//可选成员
    readonly outer : number //

}
const host : inter = {
    name : 'zhoujing' ,
    inner : 'dfdf',
    outer : 1212//只读成员初始化之后不能修改
}
interface cache{
    [name:string]:string//动态类型,不知道到底有多少子项
}
const ca:cache={}
ca.bar = 'defe'
ca.foo = 'foo'

类 class

传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件,但对于熟悉使用面向对象方式的程序员来讲就有些棘手,因为他们用的是基于类的继承并且对象是由类构建出来的。 从ECMAScript 2015,也就是ECMAScript 6开始,JavaScript程序员将能够使用基于类的面向对象的方式

class Person{
    name : string //在使用前必须声明
    age : number
    constructor(name:string,age:number){
        this.name = name
        this.age = age
    }
    sayHi(msg:string):void{
        console.log(`i am ${this.name}`)
    }
}

与es6相比,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();
访问修饰符
class Person{
   	public name : string //默认都是public
    private age : number //私有属性只能在内部访问
    protected gēnder : string
    constructor(name:string,age:number){
        this.name = name
        this.age = age
    }
    sayHi(msg:string):void{
        console.log(`i am ${this.name}`)
      	console.log(this.age)
    }
}
class Student extends Person{
    constructor(name:string,age:number){
        super(name,age)
        console.log(this.gender)//protected只允许在子类中使用
    }
}
const tom = new Person('tom',25)
console.log(tom.age)//error

总结来说,TS类声明的对象默认都是public,加不加public修饰符没啥影响,加了private修饰符之后,对象只能在内部访问了,加了protected修饰之后,只能在派生子类使用

只读属性

你可以使用 readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。

class Person{
    public name : string //默认都是public
    private age : number //私有属性只能在内部访问
    protected gender : string
    readonly sex : string //只读属性必须在声明时或者构造函数中初始化
    constructor(name:string,age:number){
        this.name = name
        this.age = age
        this.gender = 'male'
        this.sex = 'female'
 }
 sayHi(msg:string):void{
     console.log(`i am ${this.name}`)
       console.log(this.age)
 }
}

readonly属性必须在声明时或者构造函数中初始化,两者选其一,不能两个同时操作,初始化之后不管是内部还是外部都是不能改变的

抽象类

抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,抽象类可以包含成员的实现细节。 abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法

抽象类一般是需要当作继承使用,需要在子类中继承与实现,抽象类中有抽象方法时,子类必须继承

abstract class Aniaml{
    eat(food : string):void{
        console.log(`呼噜呼噜吃:${food}`)
    }
    //父类有抽象方法时,子类必须继承实现
    abstract drink(water:string):void
}

class Cat extends Aniaml{
    drink(water: string): void {
        // throw new Error("Method not implemented.")
       console.log('dwdwd')
    }

}
//这里父类定义了drink方法,所以子类必须继承实现

泛型 Generics

当我们参数类型不确定时,可以使用泛型,这样就不用重复定义函数

//当你不知道你传递的是什么类型之的时候使用范型
function createArray1 (number :number,value:number) :number[]{
    return Array(number).fill(value)
}
function createArray2 (number:number,value:string): string[]{
    return Array(number).fill(value)
}
function createArray<T> (number :number,value:T) : T[]{
    return Array<T>(number).fill(value)
}
const arr = createArray<string>(4,'number')
const arr1 = createArray<number>(4,3)