TypeScript 学废了么 ?

前面的话

项目开发中基本离不开 TypeScript 来规范 JS 的类型,这篇文章主要总结 TypeScript 的基本知识。(没有 TypeScript 的项目就像奶茶里没有奶,哈哈哈~。)

1、TypeScript 概述

在介绍前先聊一下,为什么需要使用 TypeScript ?

JS 是一种脚本语言,作为解析型语言,只能在运行时发现错误,是弱类型语言。

TS 是 JS 的超集,在编译的过程中就可以纠正错误,用于解决大型项目的代码复杂性。支持强类型、静态类型,支持模块、接口和泛型,最终被编译成 JS 代码,给浏览器使用。

TS 能在开发时帮助我们检测代码中类型定义的问题,大大增强了代码的可阅读性和可维护性。

2、TypeScript 的安装
  • 安装

    npm install -g typescript
    
  • 验证

    tsc -v
    
  • 编译

    tsc hello.ts
    

    执行该命令会生成一个 hello.js 文件

注意

  • ts 必须被编译成 js 文件之后才可以被执行。
  • ts 只会在编译阶段对类型进行检查,如果发现有错误,编译时就会报错;而运行时,生成的 js 文件与普通的 js文件一样,不会进行类型检查。
3、TypeScript 基础类型
  • boolean 类型

    let isDone: boolean = false;
    // es6 let isDone = false;
    
  • number 类型

    let age:number = 18;
    // es6 let age = 18;
    
  • string 类型

    let str:string = 'xiaoqi';
    // es6 let str = 'xiaoqi';
    
  • symbol 类型

     const sym = Symbol();
     let obj = {
        [sym]: "value"
    };
    
    console.log(obj[sym]); // "value"
    
  • Array 数组

    两种表示方式:一种是:元素类型+[];另一种是数组泛型: Array<元素类型>

     let list:number[] = [1,2,3];
     let list1: Array<number> = [4,5,6];
     // es6 let list = [1, 2, 3];
    //  es6 let list1 = [4, 5, 6];
    
  • Tuple 类型

    Tuple 类型是 TS 中特有的类型,类似于数组,但它规定了每一个位置上的类型。

    let tuple:[string,number,string,boolean] = ['xiaoqi',20,"爱前端",true]
    

    如果初始化的类型与规定的类型不匹配时,就会出错。

  • Enum 类型
    enum 枚举类型为一组数值,可以很好的实现语义化,比如各种状态码的定义

    enum Color {
        red,
        green,
        bule
    }
    
    let color:Color = Color.red;
    console.log(color); // 0
    

    默认从 0 开始,依次赋值。也可以手动赋值:

    enum Color {
        red = 4,
        green,
        bule
    }
    
    let color:Color = Color.green;
    console.log(color); // 5
    

    这样就是从 5 依次赋值,也可以全部手动赋值:

    enum Color {
        red = 4,
        green = 9,
        blue = 12,
    }
    
    let color:Color = Color.blue;
    console.log(color); // 12
    

    枚举类型除了支持 从成员名称到成员值的映射外,还支持 从成员值到成员名称 的反向映射

    enum Color {
        red = 4,
        green = 9,
        blue = 12,
    }
    
    let color:Color = Color.blue;
    console.log(color); // 12
    let colorName: string = Color[9];
    console.log(colorName); // "green"
    

    枚举类型还支持成员值是数字与字符串的混合:

    enum Enum {
        A, //0
        B, // 1
        C = "C",
        D =  "D",
        E = 8,
        F // 9
    }
    
  • any 类型

    如果在编译阶段不清楚变量的类型,可以使用 any 类型来标记。使用any 类型相当于避开了 ts 的类型检测,一般来说不建议使用。

    let value:any;
    value.trim();
    value();
    value[0][1];
    

    给 value 定义了 any 类型之后,上述的代码都不会报错。并且 any 类型的值可以赋给其他类型的值(顶级类型)。

    let value:any = 123;
    let num:number = value;
    
  • unKnown 类型

    任何类型值都可以赋给 any 类型的变量,同样任何类型值都可以赋给 unknown 类型的变量;不同的是 unknown 类型不能赋给其他类型的变量,只能赋值给any 与 unknown 类型
    any 类型太松了,一般建议使用unknown 类型

    let value2:unknown = 4;
    value2 = true;
    value2 = "hello";
    value2 = [];
    value2 = undefined;
    value2 = null; 
    

    上述代码都是 ok 的,任何类型值都可以赋值给 unknown 类型。

    let value: any = 10;
    let value2:unknown = 10;
    let value3: unknown = "hello";
    let num:number = 4;
    num = value; //  ok  
    num = value2; // Error unknown类型不可以赋给除any和unknown类型之外的类型
    value = value2;// ok unknown类型赋给any类型
    value3 = value2; // ok unknown类型赋给unknown类型
    
  • null 与 undefined 类型
    在 TypeScript 中,undefined 与 null 各自都有自己的类型分别为 undefined 和 null。

        let u: undefined = undefined;
    	let n: null = null;
    	
    	let conter:void;
    	conter = u;
    	console.log(conter);// undefined
    

    当指定了 --strictNullChecks 时,null 和 undefined 只能赋值给 void 和它们各自。

  • never 类型
    never 类型表示那些永远不存在的值的类型。任何类型都不能赋给never
    值不会存在的两种情况: 比如函数抛出异常,或者函数永远执行不完(死循环)。

    function errorFunction(): never {
        throw new Error(); // 抛出异常之后,就无法执行完
        console.log('hello');
    }
    
    function forNever(): never {
        while(true){};//下面的console 永远不会执行
        console.log('hello');
    }
    
  • void 类型

    某种程度上说,void 类型是与 any 类型相反,它表示没有任何类型。当函数没有返回值时,其返回值类型是 void。

    function user():void {
        console.log('hello'); 
       // 如果再加一个返回值,就会报错  
    }
    

    声明一个 void 类型的变量只能赋值为 undefined 和 null。(在 strictNullChecks 未指定为 true时)。

    let  unusable:void =  null;// 当开启 --strictNullChecks 时,不能赋值为 null
    unusable = undefined;
    
4、类型推断
	let num = 123;

上面的代码中,没有显示的告诉 num 是一个 number 类型,但是将鼠标放置 num 上,会发现 ts 自动把变量推断为 number 类型。

一般来说如果 ts 可以自动帮我们推断类型的时候,我们可以不用显示的为变量写类型。

const one = 1;
const two = 2;
const three = one + two;

上述代码中 ts 可以自动推断 one、two、three 的类型。

function getTotal(one, two) {
    return one + two
}
const total = getTotal(1,2);

上述的代码中,one、two、total 是 any 类型,当为 one、two 加上类型之后,total 的类型 ts 就可以帮我们自动推断。

5、类型断言

当我们确定知道变量的类型时,可以使用断言,断言的方式用两种:

  • <>

    let someValue:any = "xiaoqi";
    let strLength: number = (<string>someValue).length;
    
  • as

     let strLength:number = (someValue as string).length;
    

    除了 as 基本类型之外,还可以 as const 。在 ts 里面有一种类型拓宽,当我们分别使用 const 和 let 定义一个变量时,ts 做了什么呢?

    const a = "xiaoqi" 
    let b = "xiaoqi"
    

    此时 a 的类型是 “xiaoqi” , b的类型是 string。这里 let 声明的变量类型就被类型拓宽了。

    type Type = "a" | "b" | "c"
    let x = "a"; // 使用 const 可以避免这个问题
    
    const funTest =  (x:Type)  => {
      console.log(x)
    }
    
    funTest(x) // Error. Argument of type 'string' is not assignable to parameter of type 'Type'
    

    上述的例子正是因为 let 的类型拓宽,导致出错了。使用 const 去定义变量之后可以避免这个问题。

    除了const 可以解决类型扩宽外, as const 可以帮我们解决一部分类型拓宽的问题。

    const obj = {
     x: 1 
    }
    // obj 的类型是 {x: number}
    const obj1 = { 
      x: 1  as const ,
    };  	
    // obj1 的类型是 {x: 1}
    const obj2 = {
    	x: 1 
    } as const
    // obj2 的类型是 { readonly x: 1 }   
    

    上面这个例子中,const 也不是万能的了,里面的 x 的类型也是 number 类型了。

    当使用了 as const 之后, TypeScript 将为它推断出最窄的类型,没有拓宽。

  • 非空断言

    x! 表示将 x 排除 null 和 undefined

6、类型守卫

类型保护是可以确保类型在一定的范围内,一般用于联合类型。

  • in 关键字

    interface Student {
        teach:boolean,
        study: ()=>{}
    }
    interface Teacher {
        teach:boolean,
        skill: ()=>{}
    }
    function person (person: Student | Teacher) {
           if("skill" in person) {
             person.skill();
         }else {
             person.study();
         }    
    }
    
  • typeof 关键字

    typeof 类型保护的类型只能是:number、string、boolean、symbol。

     function padLeft(value:string,padding:string|number) {
      if(typeof padding === "number"){
          return Array(padding + 1).join(' ') + value;
      }
      if(typeof padding === "string") {
          return padding + value 
      }
      throw new Error('Expected string or number');
    }
    
  • instanceof 关键字

    class NumberObj {
      constructor(public count: number){};
    }
    
    function addObj(first: object|NumberObj, second:object | NumberObj) {
      if(first instanceof NumberObj && second instanceof NumberObj) {
        return first.count + second.count;
      }
      return 0;
    }
    
    const first = new NumberObj(6);
    const second = new NumberObj(8);
    addObj(first , second);
    
7、联合类型 、交叉类型、类型别名
  • 联合类型:表示一个值可以是几种类型之一,用 | 分割每一个类型

    let value:number|string;
    
  • 交叉类型: 将多个类型合并为一个类型,用 & 运算符进行合并 。

    type PoinX = {x:number}
    type Point = PoinX & {y: number}
    
    let point:Point = {
        x:1,
        y:2
    }
    
    • 同名基础类型属性合并

      interface A {
          a:string,
          b:number,
      }
      interface B {
          a:number,
          b:number,
      }
      
      type AB = A & B;
      
      let ab:AB= {
          a:"jjj", // Error
          b: 9,
      }
      

      接口 A 和接口 B 都有属性a,但类型不同,合并之后 a 的类型是 string & number ,很显然没有这种类型的存在,合并之后的 a 的类型是 never,就会导致报错。

    • 同名非基本类型属性的合并

      	interface C {
      	    c:string,
      	}
      
      	interface D {
      	    d: string,
      	}
      	
      	interface A {
      	    a:C,
      	    b:number,
      	}
      	interface B {
      	    a:D,
      	    b:number,
      	}
      	
      	type AB = A & B;
      	
      	let ab:AB= {
      	    a:{c:"ccc", d:"ddd"},
      	    b: 9,
      	}
      

      上面的代码中,虽然 a 属性时同名的,但是是非基本类型,所以可以合并。

  • 类型别名

    使用 type 给一个类型起一个新的名字:

    type Message = string | string[];
    let say = (message: Message) => {   
    }
    

    同样也可以重新命名多个字面量类型的联合类型:

    type Dir = "left"|"right"|"up"|"down";
    
8、可选链?.

在TypeScript 3.7中增加了可选链?.。其核心是在遇到 undefined 或者 null 时停止代码运行。

let x = foo?.bar.baz();

当 foo 是 undefined 或者 null 时 ,代码停止运行并返回 undefined。

在代码中我们可以使用?.代替&&的使用。

// 使用 &&
if(foo&&foo.bar&&foo.bar.baz) {}
// 使用 ?.
if(foo?.bar?.bar){}

注意的是,?.只判断 undefined 和 null,对于空字符串、0、NaN、false是不会像&&一样有短路逻辑的。

9、空值合并运算符 ??

TypeScript 3.7 除了引入了可选链?.也引入了空值合并运算符??。其核心在于左侧操作数为undefined或null时返回右侧操作数,否则返回左侧操作数

const foo = null ?? 'xiaoqi'
console.log(foo); // 输出:"xiaoqi"
const baz = 0 ?? 42;
console.log(baz); // 输出:0

可以看出与 || 运算符不一样的是,|| 操作符在左操作符为 ‘’ 、0、NaN时返回右侧操作数。

10、TypeScript 类
class Person {
  name = "mian"; // 默认为public,可以在类的内部、外部被使用
  private age = 20; // 只允许在类的内部使用,不允许被继承
  protected height = 162; // 只允许在类的内部使用,但是可以被继承,在子类的内部被使用
  sayHello() {
    return "hello";
  }
}
  • 继承: 使用 extends 关键字来实现继承。
class Jiejie extends Person{
  // 重写父类方法
  sayHello() {
    return super.sayHello() + "lala";
  }
  // 使用父类的 height 属性
  sayHeight() {
    console.log(this.height);
  }
}
  • 类的构造函数 constructor
class Person {
  public name:string;
  constructor(name:string) {
    this.name = name;
  }
  // 简化
  // constructor(public name: string) {}
}

super 指向父类的this,子类中只要写了constructor 就要写super, 即使父类中没有constructor,也要写super()。

class Teacher extends Person {
  constructor(public age: number) {
    super("mian");
  }
}
  • getter、setter 、static 的使用
class Jiejie {
  constructor(private _age: number) {}
  // 静态属性或方法,直接类调用
  static height: string = "jjj";
  // getter可以对传入的属性进行封装
  get age() {
    return this._age - 2;
  }
  set age(age: number) {
    this._age = age;
  }
}
  • 抽象类:使用 abstract 关键字声明的类,包含一个或多个抽象的方法。继承于抽象类的类都需要实现抽象类里面的抽象方法。
abstract class Man {
  abstract skill(): void;
}

class Waiter extends Man {
  skill() {
    console.log("点餐");
  }
}
class SupWaiter extends Man {
  skill() {
    console.log("表演点餐");
  }
}
11、TypeScript 接口

在面向对象语言中,接口是对行为的抽象,而具体的行动需要类自己实现。

TS 中的接口除了可以对类的一部分行为进行抽象以外,还可以对对象的属性做一定的描述。

  • 对象的描述

    使用接口描述一个对象,具体对象实现这个接口时,必须严格按照接口定义去实现。

    interface Person {
    	name:string,
    	age:number
    }
    
    const person = {
        name:"xiaoqi",
        age:20
    }
    
  • 可选|只读|任意属性

    interface Person {
    	readonly name:string, // 只读
    	age?:number;// 可选
    	// 还可以有其他属性,属性名为string类型,值为any类型
    	[propName:string]:any;
    }
    
    const person = {
        name:"xiaoqi",
        age:18,
        height: 163,
    }
    
  • 函数类型的描述

    接口除了可以描述带有属性的普通对象,也可以描述函数类型。

    interface AddFun {
        (value1:number, value2:number):boolean;
    }
    
    const addFun:AddFun = (val1: number,val2:number):boolean =>
    {
        if((val1 + val2) < 100 )return false;
        else return true;
    }
    
  • 类的描述

    类使用 implements 来 实现接口。

    interface Point {
        x:number,
        y:number,
        counter: (x:number,y:number)=>number,
    }
    class SomePoint implements Point {
        x = 1;
        y = 2;
        counter(x:number, y:number){
            return x + y;
        }
    }
    
  • 接口的继承

    接口使用 extends 来实现接口的继承。

    interface PartialPointX {
        x: number;
    }
    
    interface Point extends PartialPointX {
        y:number;
    }
    
    const point = {
        x:1,
        y:2,
    }
    
  • 接口与类型别名的区别

    类型别名也可以来描述对象、函数的结构,同时也可以对类的部分进行描述。

    type Point = {
        x: number,
        y:number
    }
    
    type counter = (x:number,y:number)=>boolean;
    
    
    const point:Point = {
        x: 1,
        y:8
    }
    class SomePoint implements Point {
        x = 1;
        y = 4;
    }
    

    但类型别名可以用于一些其他的类型:

    type Word = string | number;
    type Dir = "left" | "right" | "up" | "down";
    

    大多情况下使用接口描述一个类型,如果需要使用联合类型或者元组类型时,使用类型别名。

12、TypeScript 泛型

泛型: 泛指的类型,可以随意命名(但一般使用 T 表示泛型),在具体使用的时候,声明具体的类型。

function join<T> (first:T, second:T){
    return `${first} ${second}`;
}
 
join<string>("xiaoq","qi");

泛型中数组的使用:

function muFun<T>(params:T[]) {
    return params;
}
muFun<string>(['xiao','qi']);

多个泛型的定义:

function myFun<T,P>(first:T,second:P) {
    return `${first} ${second}`;
}
myFun<string,number>("xiaoqi",18);

泛型定义接口:

interface KeyPair<T, U> {
  key: T;
  value: U;
}
let kp1: KeyPair<number, string> = { key: 123, value: "str" };
let kp2: KeyPair<string, number> = { key: "str", value: 123 };

类中的泛型与继承:

 interface Girl {
     name:string,
 }
class SelectGirl <T extends Girl> {
    constructor(private girls:  T[]) {}
    getGirl(index: number): string {
        return this.girls[index].name;
    }
}
const girl = new SelectGirl<{name:string,age:number}>([{name:'mian',age:18},{name:"xiaoqi",age:19}]);
console.log(girl.getGirl(1));

泛型约束:

type InitValue = {
  id: number
  dealer_id: number | undefined
  arrive_time: string
}
// T 类型继承了 keyof InitValue 即 "id" | "dealer_id" | "arrive_time"
const handleChange = <T extends keyof InitValue>(
    curValue: InitValue[T],
    curIndex: number,
    type: T,
  ) => {
   // 
}
handleChange( 8, 3, "id") // 调用的时候这里 T 指定了明确的类型 'id'

这样 T 表示 InitValue 键中的任意类型。

13、typeof | keyof
  • typeof

    typeof 除了可以做类型保护,还可以获取一个值的类型

    const person =  {name:"xiaoqi", age:20} 
    type Sem = typeof person;
    const sem:Sem = {
      name:'zhang',
      age:20
    }
    
  • keyof

    可以获取某种类型的所有键,其返回类型是一个联合类型

    interface Person {
      name: string;
      age:number;
    }
    type K = keyof Person; // "name"|"age
    type K2 = keyof Person[];// number|"length" | "toString" | "toLocaleString" | "pop" | "push" | "concat" | "join" | "reverse" | "shift" | "slice" | "sort" | "splice" | "unshift" | "indexOf" | "lastIndexOf" | ... 13 more ... | "values
    type K3 = keyof {[x:string]:Person};// string | number
    
    class Eg2 {
      private name: string;
      public readonly age: number;
      protected home: string;
    }
    // T为 age
    // 而name和home不是公有属性,所以不能被keyof获取到
    type T = keyof Eg2
    

T为 age 而 name 和 home 不是公有属性,所以不能被 keyof 获取到

14、泛型工具
  • Partial< T>

使用Partial<T>可以将一个T中属性变为可选的。

export type FilterParams = {
  create_start: number
  create_end: number
  phone: string
  channel_id: number
  city_id: number
}

// FilterParamsOption 中的属性都是可选的
type FilterParamsOption = Partial<FilterParams>
// 即
type FilterParamsOption = {
  create_start?: number
  create_end?: number
  phone?: string
  channel_id?: number
  city_id?: number
}

// 实现
type Partial<T> = {
	[P in keyof T]?: T[P]
}
// [P in keyof T] 遍历T上的所有属性
// ?:设置为属性为可选的
// T[P] 类型为原类型
  • Required< T>

使用Required<T>可以将T中属性变为必选。

export type FilterParams = {
  create_start: number
  create_end: number
  phone?: string
  channel_id?: number
  city_id?: number
}

// FilterParamsOption 中的属性都是可选的
type FilterParamsOption = Partial<FilterParams>
// 即
type FilterParamsOption = {
  create_start: number
  create_end: number
  phone: string
  channel_id: number
  city_id: number
}

// 实现
type Required<T> = {
  [P in keyof T]-?: T[P]
}
  • Pick<T, K>

将T类型中的K键列表提取出来,生成新的类型

export type FilterParams = {
  create_start: number
  create_end: number
  phone: string
  channel_id: number
  city_id: number
}

type FilterParamsOption = Pick<FilterParams, 'phone' | 'city_id'>
// 即
type FilterParamsOption = {
    phone: string;
    city_id: number;
}

// 实现
type Pick<T, K extends keyof T> = {
	[P in k ]?: T[P]
}
  • Exclude<T, U>

去除联合类型T与联合类型T的交集,返回T剩余的部分。

type FilterParams = {
  create_start: number
  create_end: number
  phone: string
  channel_id: number
  city_id: number
}
type FilterParams2 = {
  title: string
  city: number
  phone: string
  channel_id: number
  city_id: number
}

type FilterParamsOption = Exclude<keyof FilterParams2, keyof FilterParams>
// 即
type FilterParamsOption  = "title" | "city"

// 实现
type Exclude<T, U> = T extends U ? never : T
  • Extract<T, U>
    与 Exclude 相反,取 联合类型T与联合类型U的交集
type FilterParams = {
  create_start: number
  create_end: number
  phone: string
  channel_id: number
  city_id: number
}
type FilterParams2 = {
  title: string
  city: number
  phone: string
  channel_id: number
  city_id: number
}

type FilterParamsOption = Extract<keyof FilterParams, keyof FilterParams2>

// 即
type FilterParamsOption  = "city_id" | "phone" | 'channel_id'

// 实现
type Extract<T, U> = T extends U ? T : never;
  • Omit<T, K>

与 Pick<T, K> 相对应,是将T类型中K键值去掉,形成新的类型。

export type FilterParams = {
  create_start: number
  create_end: number
  phone: string
  channel_id: number
  city_id: number
}

type FilterParamsOption = Omit<FilterParams, 'phone' | 'city_id'>
// 即
type FilterParamsOption = {
  create_start: number
  create_end: number
  channel_id: number
}

// 实现
type Omit = Pick<T, Exclude<keyof T, K>>
  • Record<K, T>

可以生成一个以K类型为键,以T类型为值的类型

type FilterParams = {
  date: string[];
  phone: string;
  channel_id: number;
  city_id: number;
}
type FilterParamsOption = Record<string, FilterParams>
// 即
type FilterParamsOption = {
  [p: string]: FilterParams
}
// 实现
type Record<K extends string | number | symbol, T> = { [P in K]: T; }
  • Parameters< T >

返回 T 函数的参数类型,并将每个类型放在一个元组中。

type Foo = (x: string, y: number) => string | number
type FooType = Parameters<Foo>;  // string | number
// 即
type FooType = [x: string, y: number]
// 实现
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

1、Parameters 中参数T必须是一个函数类型,所以 T 必须继承与(…args: any) => any 或者 Function
2、具体实现:判断T是否属于函数类型,属于则使用infer让 ts 自动推断函数参数的类型并赋给 P,将P返回;否则返回never。
3、infer 关键词只能在extends条件上使用

使用infer实现获取一个数组各元素的类型:

type ArrType<T extends Array<any>> = T extends Array<infer P> ? P : never

type A = ArrType<[ 'xiaoqi', 20]>
// 即
type A =  'xiaoqi' | 20
  • ReturnType< T>

返回 T(函数)的返回值的类型

type Foo = (x: string, y: number) => string | number
type FooType = ReturnType<Foo>;  // string | number
// 即
type FooType = string | number

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer P? P : never;
  • ConstructParameters< T>

获取类的构造函数的参数类型,并存在一个元组中。

class Person {
	constructor(public name: string, age?: number) {}
}

type E1 = ConstructParameters<typeof Person>
// 即 
type E1 = [name: string, age?: number | undefined]

// 实现
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;

1、T 必须是一个拥有构造函数的类
2、T 必须是继承一个抽象类(只有抽象类型能同时被抽象类和普通类)

class Test {}
abstract class Test2 {}

// typeof可以获取一个值类型
// 正常赋值
const E1: typeof Test = Test
// 报错: 抽象类不能赋值给非抽象类型
const E2: typeof Test = Test2
// 正常赋值
const E3: typeof Test2 = Test
// 正常赋值
const E4: typeof Test2 = Test2

3、使用作为类型和使用typeof 类作为类型的区别

class Greeter {
    greeting: string; // 实例属性
    constructor(message: string) {
        this.greeting = message;
    }// 构造函数
    greet() { // 实例方法
        return "Hello, " + this.greeting;
    }
    static PI: number = Math.PI;// 静态属性
    static hi() {} // 静态方法
}
// 正常赋值
const e1:Greeter = new Greeter('xiaoqi')
// 等号后面的Greeter报错: 类型“typeof Greeter”缺少类型“Greeter”中的以下属性: greeting, greet
const e2:Greeter = Greeter
// 正常赋值
const e3: typeof Greeter = Greeter
// 报错:类型'Greeter'缺少类型'typeof Greeter'中的以下属性:prototype, hi,PI
const e4: typeof Greeter = new Greeter('xiaoqi')

1、使用作为类型,这种类型约束所赋的值必须是该类的实例。这个类型包含类的所有实例成员和构造函数
2、使用typeof 类作为类型,这种类型约束所赋值的类型属于该类型。这个类型包含了类的所有静态成员和构造函数。

  • 其他工具类型
//字符串转大写
type Eg1 = Uppercase<'abcd'>;
// 即
type Eg1 = 'ABCD'


// 字符串转小写
type Eg2 = Lowercase<'ABCs'>;
// 即
type Eg2 = 'abcs'


// 首写字母转大写
type Eg3 = Capitalize<'abcd'>;
// 即
type Eg3 = 'Abcd'


// 首写字母转小写
type Eg4 = Uncapitalize<'ABCD'>;
// 即
type Eg4 = 'aBCD'
15、特殊注释
  • @ts-nocheck:在文件顶部加上可以使文件跳过ts检查

  • @ts-check:在.js文件顶部加上可以让这个文件进行ts检查。搭配JSDoc标签使用。

    1、变量声明:使用@type标签

    // @ts-check
    
    /** @type {number} */
    let a = 0;
    a = ""; // 报错 不能将类型“string”分配给类型“number”。
    

    2、函数类型声明:使用@params和@returns标签

    /**
     * @param {number} b
     * @param {number} c
     * @returns {string}
     */
    const sum = (b, c) => {
        return b + c; // 报错 不能将类型“number”分配给类型“string”。
    };
    

    3、类声明: 使用@public 、@private、 @protected、@readonly、@static等

    class Test {
        constructor() {
            /** @private */
            this.a = 100;
            /** @readonly */
            this.b = 50;
        }
    }
    
    const test = new Test();
    console.log(test.a); // 报错 属性“a”为私有属性,只能在类“Test”中访问。
    test.b += 1; // 报错 无法分配到 "b" ,因为它是只读属性。
    
  • @ts-ignore 可以忽略ts报错。上例中加上 @ts-ignore,ts将不会报错,但如果eslint中配置了禁止使用@ts-ignore,eslint会报错。(@ts-expect-error 也可以实现一样的效果)

    const sum = (b, c) => {
        // @ts-ignore
        return b + c;
    };
    
尾声

笔记的基础内容来自了 博主技术胖的 TypeScript 从入门到精通图文视频教程。

  • 7
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值