ts快速上手

前言

前段时间学习TS,一直没时间总结,今天乘着有时间,我将我在学习过程中的一些核心知识整理成文,方便以后查阅

本文特点:小巧,几分钟可以快速看完

收获:阅读本文,你将可以快速上手JS,了解TS的核心基础知识

附:本文结构预览,如下

简介

TypeScriptJavaScript的超集,为大型应用而生。

有两个特点:

一是强类型;

二是基于类的面向对象编程

数据类型

TS中的数据类型有很多,如下:

  1. Number类型
let a: number = 5
复制代码

如上,声明一个Number类型的a并赋值为数字5;可以看TS中声明变量数据类型时,格式为变量名后面加: xx类型

  1. String类型
let str: string = 'hello ts'
复制代码
  1. Boolean类型
let isDone: boolean = true
复制代码
  1. NullUndefined类型
let n1: null = null
let u1: undefined = undefined
// -------------------------------
let n2: null = undefined
let u2: undefined = null
复制代码

定义为null或者undefined类型的变量,赋值可以为nullundefined其中之一

  1. Void 类型
function fn():void{
    console.log('This is a fn,but return is void')
}
复制代码

void用于表示返回空

  1. Any类型
let any1: any = 'xxx'
复制代码

Any类型的变量可以赋值任意类型的值 7. Array 类型

let arr: number[] = [1, 2, 3];
//或者
let arr: Array<number> = [1, 2, 3]; 
复制代码
  1. Enum类型
enum Direction {
  NORTH,
  SOUTH,
  EAST,
  WEST,
}

let dir: Direction = Direction.NORTH;
复制代码

需要注意,以上仅列举了部分常用的数据类型,其他可移步官网

类型声明

TS中提供了一些基本类型,另外类也可以当类型。但是有的时候我们需要一些更灵活的类型,这就需要自定义一些类型或者叫类型声明

声明类型需要借助一个关键字type 例如

type User = {
    name: string;
    age?: number;
}
复制代码

以上代码定义了一个User类型,该类型必须有name属性类型为string,可以选择有或者没有类型为numberage属性

let user: User;
user = {
    name: 'Alice'
}
复制代码

上述代码,声明一个user变量要求是我们定义的User类型并赋值,赋值时需要值与定义的类型对应

当然不仅仅用于变量,自定义类型跟普通类型一样,可以用于所有能用类型的地方,没有限制,比如函数的形参等等

function show(obj: User) {
    console.log(obj.name)
}
show(user);
复制代码

可以看到使用type关键字可以很方便的创建一个新类型

类型断言与类型守卫

先来看个例子

type User = {
    name: string;
    age: number;
}
function showUser(user: User) {
    console.log(user.name);
    console.log(user.age);
}
showUser({ name: 'Alice', age: 12 })
复制代码

如上,showUser函数执行传递的参数是符合类型要求的。但是如果不符合要求的参数就会报错

let errorType = '';
showUser(errorType); //错误
复制代码

正常编写代码一般不会出这样的问题,但是这个数据有可能来自运行时的其他地方(比如数据库、第三方库、用户输入等)。 我们知道语言在运行时是不具有类型的,那我们在运行时如何保证和检测来自其他地方的数据也符合我们的要求呢? 这就类型断言要干的事

所谓断言就是断定、确定、绝对的意思;所以简单来讲,类型断言就是保证数据类型一定是所要求的类型

类型断言还需要借助类型守卫函数,类型守卫函数就是用于判断未知数据是不是所需类型

function isUser(arg: any): arg is User {
    if (!arg) {
        return false;
    }
    else {
        if (typeof arg.name == 'string' && typeof arg.age == 'number') {
            return true;
        } else {
            return false;
        }
    }
}
复制代码

可以看到类型守卫函数与普通函数没多大区别,唯一需要注意其返回值类型比较特殊特殊,格式:x is y ,表示x是不是y类型

if (isUser(errorType)) {
    showUser(errorType);
}
复制代码

经过这样的类型断言后就不会报错了

类(class)和修饰符

我们知道,类class出现的目的,其实就是把一些相关的东西放在一起,方便管理

类中包含两个东西(也叫成员):

  1. 属性
  2. 方法

类的成员就是类中所有的属性和方法

TS中通过class关键字可以方便的定义一个类

class Person{
  name:string;
  age:number;
  show(){
    console.log(`我叫${this.name},今年${this.age}了`);
  }
}
复制代码

通过new关键字可以方便的生产一个类的实例对象,这个生产对象的过程叫实例化

let  p1 = new Person('Alice',12)
复制代码

如上,p1就是Person类的一个实例

还有一点需要注意,就是在实例在new出来的时候,它实际是调用了类中的一个方法进行初始化,这个方法被叫做构造器;一般都会在类中显示地写上constructor方法,如果没有显示定义的constructor,就会调用系统隐示的constructor

constructor(name:string,age:number){
  this.name = name;
  this.age = age;
}
复制代码

类中的成员修饰符

访问修饰符

访问修饰符的作用就是用于限制别人乱用类中的东西

  1. public 公开的,谁都能用(默认public)

  2. private 私有的,仅类自己里头才能使用

  3. protected 受保护的,仅仅类和类的子类能使用

使用访问修饰符的建议:尽量使用private,一般所有属性都是private,要想访问私有属性可以通过访问器

class Person{
  private _num:number = 12;
  public get num(){
    return this._num;
  }
  public set num(val:number){
    this._num =  val;
  }
}
let p1 = new Person();
console.log(p1.num)
p1.num = 5;
console.log(p1.num)
复制代码

事实上ts的访问器其实借助的就是js的访问器,而js的访问器是到高版本里才有的 所以在通过tsc命令编译的时候有个注意点: ts默认生成ES4的代码,我们编译时需要通过--target 某版本指定ts编译的版本

tsc --target ES5 1.js
复制代码

当然也可以在tsconfig.json文件中配置 访问器的好处在于:安全和方便

只读修饰符

readonly 只能读不能写

class Person{
  readonly name = 'Alice';
}
let p = new Person();
console.log(p.name);
复制代码

需要注意的时,即使是readonly的东西,在初始化之前是可以写,即在constructor中可以初始化或更改

class Person{
  readonly name:string;
  constructor(name:string){
    this.name =  name;
  }
}
复制代码

所以,我们知道了,readonly的属性,仅两个地方可以写:

  1. 在声明同时赋予初始值
  2. 在构造函数中赋值或者修改初始值

静态修饰符

static静态的 通过static修饰的成员叫静态成员,静态成员无需实例化,直接通过类名调用

class Person{
  static a = 98;
}
console.log(person.a)
复制代码

静态成员通常用于整个类所共有的一些东西

注意点

以上三种修饰符:访问修饰符、只读修饰符和静态修饰符可以组合修饰同一成员 但需要注意

  1. 修饰符是可选的,在没有写任何修饰符,默认有个public
  2. 同类修饰符只能有一个
  3. 三种修饰符有先后顺序,分别是:访问、静态、只读 即:【public/static/protected】 【static 】【readonly】

类的继承

我们知道js中有继承,最开始js是使用函数来模拟实现类的,一直到ES6出现,才开启了class以及extends 等相关关键字的使用。那为什么会有继承呢? 事实上,继承的好处在于,可以更好的重用代码,以及后期更好的维护代码

TS中的继承ES6中的类的继承极其相识,子类可以通过extends关键字继承一个类 例如:

class Person{
  name:string;
  age:number;
  constructor(name,age){
    this.name = name;
    this.age = age;
  }
}
class student extends Person{
  score:number;
  constructor(name,age,score){
    super();
    this.score =  score;
  }
}
复制代码

可以看见,跟ES6一样,子类构造函数必须加上super()执行父类的构造constructor函数

所以,大家常常说,一个子类实例,同时也是父类的实例

继承的格式:

class A {}
class B extends A {
  constructor() {
    super();
  }
}
复制代码

如上,B继承A,那B被称为父类(超类),A被称为子类(派生类) 子类实例是可以继承父类所有的publicprotected的属性和方法

除了继承,面向对象还有一个特征:多态 js和ts中多态其实很常见,可以理解为多种状态,比如代码在运行时才能决定具体执行哪个函数

抽象类

抽象就是指不具体的,所以抽象类就是指不具体的类。所以抽象类自身没有什么功能,通常作为父类类使用

定义一个抽象类,使用abstract class两关键字定义

abstract class A{
  abstract fn():number;
}
复制代码

抽象类规定了所有继承自它的非抽象子类必须实现它的所规定的功能和相关操作,否则会报错

class B extends A{
  constructor(){
    super();
  }
  fn():number{
    return 1
  }
}
复制代码

需要注意,抽象类仅仅作为基类,不能new

let b = new B();//可以
let a = new A();//报错
复制代码

接口

接口是一种规范,跟抽象类有点类似

通过 interface关键字定义接口,格式如下:

interface xxx{
  属性: 类型 ;
  ...
  (函数参数) : 返回值类型
  ...
}
复制代码

interface一般用于规范三个东西:

  1. 函数
  2. 构造器

函数interface

函数interface可规范函数的参数及返回值

interface xxx{
    (参数,...):返回值类型
}
复制代码

例如

interface SearchFn {
    (key: string, page?: number): number[]
}
const search: SearchFn = function (key: string, page: number) {
    return [1, 2, 3]
}
复制代码

我们可以看到,interface规范函数时,interface相当于type 当一个函数类型是接口时,要求:

  1. 参数名可不一致,但参数的值类型必须与接口定义的对应,且参数可以少不可多;
  2. 返回值必须有,且与接口定义的一致;

类interface

我们知道,继承的好处是复用代码,并且层级关系清晰。但JavaScript中继承是单继承,一个类只能有一个父类。而在TypeScriptinterface会显得更加灵活,因为interface可以多实现 例如:

interface serialization {
    toJSON(): object;
    formJSON(json: object): void;
}
class Box implements serialization {
    width: number;
    height: number;
    constructor(width:number,height:number){
        this.width = width;
        this.height = height;
    }
    toJSON(): object {
        return { width: this.width, height: this.height }
    }
    formJSON(json: object): void {
        if (isSize(json)) {
            this.width = json.width;
            this.height = json.height;
        }
    }
}
function isSize(json: any): json is { width: number, height: number } {
    if (typeof json != 'object') {
        console.log('必须是object类型');
    } else {
        if (typeof json.width != 'number' || typeof json.height != 'number') {
            console.log('width 和 height 必须是number类型!!')
        }
    }
    return true;
}
let box = new Box(50,50)
复制代码

如上,通过implements关键字可以让一个类实现一个接口,要求必须实现时间接口定义的方法,否则会出错

构造函数interface

构造函数interface比较特殊,是通过赋值的形式来实现,并且得跟普通interface区分开,普通interface还是使用implements。另外在接口中使用new指代构造器

interface BoxConstructorInterface{
    new (a:string)
}
interface BoxInterface{
    show(a:number):void;
}
const Box:BoxConstructorInterface = class implements BoxInterface {
    private a:string;
    constructor(a:string){
        this.a = a;
    }
    show(a:number){
        console.log(this.a)
    }
}
复制代码

另外,跟类一样,interface也能继承另外一个interface 例如:

interface A { }
interface B extends A { }
class C implements B { }
复制代码

所以,我们知道了,接口本身只是一种规范,里头定义了一些必须有的属性或者方法,接口可以用于规范functionclass或者constructor,只是规则有点区别

泛型

泛型可以理解为宽泛的类型,通常用于类和函数

泛型类

泛型可以用于类和构造器,例如:

class Person<T>{
    private _value: T;
    constructor(val: T) {
        this._value = val;
    }
}
let p = new Person<number>(12)
复制代码

如上,<T>表示传递一个T类型,在new的时候才把具体类型传入。其中T是变量可改,但通常比较常见就是写T 之前说TypeScript类型的时有说到数组,其实数组本质就是一个泛型类

let a = new Array<number>();
复制代码

泛型函数

泛型可以用于普通函数,例如:

function fn<T>(arg: T): T {
    return arg;
}
fn<number>(12);
复制代码

其实不管是用于类还是用于函数,核心思想都是:把类型当一种特殊的参数传入进去

需要注意的是泛型也可以“继承”,但表示的是限制范围 例如

class Person<T extends Date>{
    private _value: T;
    constructor(val: T) {
        this._value = val;
    }
}
let p1 = new Person(new Date())

class MyDate extends Date{}
let p2 = new Person(new MyDate())
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值