Typescipt干货解读

首先声明,以下文章都是我自己粗鄙的理解,不喜欢请留下意见,哪里写的不对也请挑出,互相学习改正

类型注解&类型推断

类型注解

例:

let count: number;
count = 123;

意思是显示的告诉代码,我们的count变量就是一个数字类型,这就叫做类型注解

这之后你再把count改成字符串就会报错

要注意的是尽管有错误,js文件还是被编译创建了。 就算你的代码里有错误,你仍然可以使用TypeScript。但在这种情况下,TypeScript会警告你代码可能不会按预期执行。

类型推断

let countInference = 123;

这时候我并没有显示的告诉你变量countInference是一个数字类型,但是如果你把鼠标放到变量上时,你会发现 TypeScript 自动把变量注释为了number(数字)类型,也就是说它是有某种推断能力的,通过你的代码 TS 会自动的去尝试分析变量的类型。

点这里演示代码

函数参数和返回值

// 函数参数和返回值
function getTotal(one: number, two: number): number {
  return one + two;
}
// 函数无返回值时,类型是void
function sayHi(): void {
  console.log('我说嘿,你说--')
}


// 函数传参是对象
function add ({one, two}: {one: number, two: number}): number {
  return one + two + ''
}
function getNumber({one}: {one: number}) {
  return one
}
function anything (one) {
  return one
} // 不注解默认是any

点击这里演示代码

对TS支持好的IDE

webstorm2020.2以上 vscode都对TS有很好的提示效果

数组类型

let numberArr = [1, 2, 3]
numberArr = [1, '']


const numberArr1: number[] = [1, 2, 3]
const undefinedArr : undefined[] = [undefined, undefined]


const arr: (string | number)[] = [1, 2, ' ']


// 对象数组
const chengxuyuan: {name: string, age: number}[] = [
  {
    name: 'yueshuang',
    age: 16
  },
  {
    name: 'chongwei',
    age: 20
  }
]
// 类型别名
type Chengxuyuan = {
  name: string
  age: number
}
// 重写
const chengxuyuan2: Chengxuyuan[] = [
  {
    name: 'yueshuang',
    age: 16
  },
  {
    name: 'chongwei',
    age: 20
  }

点我演示

元组的出现

元组类型允许表示一个*已知元素数量和类型*的数组,各元素的类型不必相同

let x: [string, number] = ['', 2]


// 使用场景:一般用于csv这种罗列,别的?
const chengxuyuan: [string, string, number][] = [
  ["xiaohong", "xiaobai", 18],
  ["jiwenge", "jiagoushi", 28],
  ["cuihua", "teacher", 25],
];

接口interface

  • 与类型别名的区别

    1. type date = string | number 类型别名可以是这种形式,也可以是type g = string | number[]接口必须是:
    2. 什么时候使用类型别名?答:无法用接口来描述一个类型,且需要使用联合类型或元组时
    3. 尽量使用接口
    4. 类型别名不能被extends和implements
interface StringObj {
name: string
other: string
}
  • 能不能写任何对象的属性都不被约束?
const obj: {
  name: string,
  age: number,
  [prototype: string]: any
} = {
  name: '',
  age: 18,
  other1: '',
  other2: 8
}
  • 也可以对方法进行约束
interface Chenxuyuan {
  name: string
  age: number
  say(): string // 方法的返回值需是string
}

类的概念

重写

好玩的例子:

class Chengxuyuan {
  content = '好的, 这个需求马上做'
  say() {
    return this.content
  }
}


let xiaojing = new Chengxuyuan() // 晓静赶紧反馈
console.log(xiaojing.say())


// 继承
class Lihaidechengxuyuan extends Chengxuyuan {
  saySomething() {
    return '但是,这个需求要排期...'
  }
}


let chongwei = new Lihaidechengxuyuan() // 崇伟非常的理智
console.log(chongwei.say())
console.log(chongwei.saySomething())


// 重写
class NPchengxuyuan extends Chengxuyuan {
  say() {
    return '这个需求做不了!'
  }
  saySomething() {
    return super.say() // 子类调用父类方法
  }
}
let brotherBo = new NPchengxuyuan()  // 当产品遇见波哥
console.log(brotherBo.say())
console.log(brotherBo.saySomething(

点我演示

类的访问类型 public private protected

类的内部和外部

public

意思就是允许在类的内部和外部被调用

// 随便写一个类
class Person {
  name: string = ''
}


const person = new Person()
person.name = '我是打工人'
console.log(person.name) // 我是打工人

这时候可以打出我是打工人是因为我们如果不在类里对name的访问属性访问类型进行定义,那么它就会默认是public访问属性。

相当于:

class Person {
    public name:string;
}

private

// private
class Person2 {
    private name:string;
    public sayHello(){
        console.log(this.name + 'say Hello')  //此处不报错
    }
}
//-------以下属于类的外部--------
const person2 = new Person2()
person2.name = 'haha'    //此处报错
person2.sayHello()
console.log(person2.name)  //此处报错

protected

// protected
class Person3 {
  protected name: string
  public sayHello() {
        console.log(this.name + 'say Hello')  //此处不报错
  }
}
class Chengxuyuan extends Person3 {
  say() {
    return this.name // 在继承中可以被使用
  }
}
//-------以下属于类的外部--------
const person3 = new Chengxuyuan()
person3.name = 'haha'    //此处报错,在外部还是不行
person3.sayHello()
console.log(person3.name)  //此处报错,在外部还是不行

总结:

  1. 如果是private,只要是在类外部使用就会报错
  2. 如果是Protected,在类外部调用也会报错,但是,protected的属性可以在继承中被使用,但子类中在外部使用还是不行

类的构造函数

// 简约写法
class Person{
    constructor(public name:string){
    }
}


// 继承
class Codeman{
    constructor(public name:string){}
}


class Teacher extends Codeman{
    constructor(public age:number){
        super('hahaha')
    }
}
const teacher = new Teacher(18)
console.log(teacher.age) // 18
console.log(teacher.name) // hahah

点我演示

规则:

  1. 在子类里写构造函数时,必须用super()调用父类的构造函数,如果需要传值,也必须进行传值操作
  2. 就算是父类没有构造函数,子类也要使用super()进行调用,否则就会报错
  3. 父类constructor中参数有几个,子类super中就应该传几个,否则也会报错

类的getter setter和static

// 从网红直播看getter
class Xiaojiejie {
  constructor(private _age: number){} // 小姐姐的真实年龄,不可以随便告诉别人
  get age() {                         // 你要是非要问呢,那就报给你一个假年龄
    return this._age - 3
  }
}
let wanghong = new Xiaojiejie(35)     // 假设这个网红35岁了
console.log(wanghong.age)             // 得到网红的年龄是32


// 从小朋友想去KTV看setter
class KTVPlayer {
  constructor(private _age:number){}
  get age(){
      return this._age
  }
  set age(age:number){
    this._age = age + 5
  }
}
let xiaojie = new KTVPlayer(15)       // 小洁未满18岁,不让去KTV玩
xiaojie.age = 18                      // kTV给小洁伪造年龄
console.log(xiaojie.age)              // 现在小洁23岁

点我演示

static 不想new对象,直接用

class Girl {
  static sayType() {
    return "我是慢热型";
  }
}
Girl.sayType = () => {
  return '你是高冷型'
}
console.log(Girl.sayType()); // 你认为你慢热,但是我认为你就是高冷

抽象类和只读属性

只读属性

class Person {
  public readonly _content: string = ''
  constructor(content: string) {
    this._content = content
  }
}
let shenteng = new Person('我年轻时候可是校草')
console.log(shenteng._content) // 我年轻时候可是校草
shenteng._content = '你太胖了,根本不是校草' // 报错,不许改,气死你

abstract抽象类 抽象方法 (此处cue晓静)

  • 抽象方法必须在抽象类中才能使用
  • 一般抽象类不被直接实例化使用,而是被用于 一个 约束子类必须给我实现 的方式
  • 抽象方只定义名字和类型,是不在里面写具体实现的。
  • 抽象方法必须在子中实现,否则子类会报错
abstract class FrontEnd {
  abstract skill(): string       // 前端工程师必须在简历里填写技能
}


class Basic extends FrontEnd {
  skill() {
    return '我是初级小白'         
  }
}

点我演示

联合类型和类型保护(类型守护)as in typeof instanceof

用as进行类型断言

类型断言有两种,as和<>形式,但是由于尖括号对jsx不友好,所以一般尽量用as

interface Basic {
  highT: boolean;
  code: () => {}
}


interface High {
  highT: boolean;
  ppt: () => {};
}


function judgeWho(animal: Basic | High) { 
  if (animal.highT) {
    (animal as High).ppt(); // 高T做PPT
  }else{
    (animal as Basic).code(); // 普通小白写代码
  }

用in

function judgeWhoTwo(animal: Basic | High) {
  if ("ppt" in animal) {
    animal.ppt();
  } else {
    animal.code();
  }
}

typeof

// typeof
function add(first: string | number, second: string | number) {
  if (typeof first === "string" || typeof second === "string") {
    return `${first}${second}`;
  }
  return first + second;
}

枚举类型

反向查询只能是数字的时候才可以

enum constant {
  'one' = 1,
  'two',
  'three'
}


// console.log(constant[3])


enum g {
  xixi,
  haha
}


// console.log(g['xixi']) // []内必须是字符串


enum test {
  name = '名称',
  age = '年龄',
  show = '秀'
}


console.log(test['名称']) /

装饰器

链接

其他

  • Omit用来剔除 复用的类型中的某些属性
interface User {
  id: number
  role: string
  name: string
  token: string
}


type UserWithoutTOken = Omit<User, 'token'>


let obj: UserWithoutTOken = {
  id: 2,
  role: 'string',
  name: 'string'
  • 泛型在jsx中会被当做标签,用extends化解
const toArray = <T extends {}>() => {}
  • keyof的用法
// 索引查询
interface Rectangle {
    x: number;
    y: number;
    width: number;
    height: number;
}


type keys = keyof Rectangle;


// 这里使用了泛型,强制要求第二个参数的参数名必须包含在第一个参数的所有字符串索引中
function getRectProperty<T extends object, K extends keyof T>(rect: T, property: K): T[K] {
    return rect[property];
}
// 传入两个参数 rect 和 property 返回 rect的属性值 rect[property]
// rect的类型假定为T  property的类型假定为K 那么返回的类型则是T[K]
// 设置泛型的时候 定义T是object类型的 T extends object
// 设置K是T的属性  K extends keyof T
let rect: Rectangle = {
    x: 50,
    y: 50,
    width: 100,
    height: 200
};


console.log(getRectProperty(rect, 'width')
  • Partial类型
// Partial类型,定义不必填属性
// 该类型已内置在TypeScript中
// type Partial<T> = {
//     [P in keyof T]?: T[P]
// };


interface Rectangle {
    x: number;
    y: number;
    width: number;
    height: number;
}


type PartialRectangle = Partial<Rectangle>;
// 等价于
// type PartialRectangle = {
//     x?: number;
//     y?: number;
//     width?: number;
//     height?: number;
// }


// let rect: PartialRectangle = {
//     width: 100,
//     height: 200
// };


let rect: PartialRectangle = {
    width: 100,
    height: 200
  • Pick类型 - 捡出需要的属性
// // 该类型已内置在TypeScript中
// type Pick<T, K extends keyof T> = {
//     [P in K]: T[P]
// };


interface User {
    id: number;
    name: string;
    age: number;
    gender: number;
    email: string;
}


type PickUser = Pick<User, "id" | "name" | "gender">;
// 等价于
// type PickUser = {
//     id: number;
//     name: string;
//     gender: number;
// };


let user: PickUser = {
    id: 1,
    name: 'tom',
    gender: 1,
  • Exclude - 剔除不需要的属性, 跟Omit有点像
// 该类型已内置在TypeScript中
// 这里使用了条件类型(Conditional Type),和JS中的三目运算符效果一致
// type Exclude<T, U> = T extends U ? never : T;


interface User {
    id: number;
    name: string;
    age: number;
    gender: number;
    email: string;
}


type keys = keyof User; // -> "id" | "name" | "age" | "gender" | "email"


type ExcludeUser = Exclude<keys, "age" | "email">;
// 等价于
// type ExcludeUser = "id" | "name" | "gender

tsconfig.json

  • include exclude
  • removeComments 编译后去掉注释
  • noImplicitAny: true 不用非设置any
  • node是遵循tsconfig.json的配置的,即,若include中没有某文件,node去执行编译的时候也是不会编译的
  • rootDir outDIr 源文件 -> 编译后文件的地址
  • noUnusedLocals noUnusedParameters 不用的变量和参数 回收删除
  • 配置解释地址

chidaozhi
60 声望4 粉丝

前端老阿姨