TypeScript的使用(上)

时间:2022-10-14 21:52:07

1. 概念

TypeScript是javaScript的超集,是对JavaScript的补充,提供了类型检测和class面向对象语法一级对es6语法的支持。

为什么要使用typescript?
当项目体量复杂庞大的时候使用ts为前端代码添加类型检测功能,更有利于合作编程和代码维护。

2. 基础类型

2.1 javascript的内置类型: boolean、number、string、undefined、null、Array

 const bol : boolean = true; // 布尔类型
 conts str : string = 'hello typescript!'; // 字符串类型
 const num : number = 1024; // 数字类型
 const undef : = undefined; // undefined类型
 const null : = null; // null类型

 // 在typescript中数组类型有两种声明方式
 const arr1 string[] = ['1','2','3'];
 const arr2 Array<number> = [1,2,3];

对于数组中包含多种数据类型的可以Tuple(元组)进行声明

const arr: [string, number] = ['1',2];

2.2 对象类型

对象类型的声明分为两种:

  • 对象本身的属性通过interface去定义和实现
  • Object.prtotype上的属性使用Object类型去声明
    // 定义对象属性
     interface User{
      name: string,
      age: number,
      getName: () => string,
     }
     const jack : User = {
      name: 'jack',
      age: 21,
      getName: () => 'jack';
     };
     
    // 定义从Object继承的属性
    const tom : Object  = {};
    tom.hasOwnProperty();
    

2.3 函数类型

// 使用interface定义函数类型
interface HelloWord{
  (name:string) : string
};

const helloWord = (name:string)=>{
  return  name;
};

// 直接定义函数类型
const helloWord: HelloWord = (name:string)=>{
  return  name;
};

3 其它类型

3.1 枚举类型 enum
默认value为数值类型,第一项为0,依次递增。枚举类型除了做类型限制还有一个用处就是内容映射。

enum Color{
  Red,
  Green,
  Blue,
};
const color: Color = Color.Red; //0
const color1: Color = Color.Blue; //1

//字符串类型的枚举
emun Test {
  A = 'a',
  B = 'b',
  C = 'C',
  D = 'D',
}
const f : Test = Test.A; // 'a'

//异构
emun Foo {
  A,
  B,
  C = 'c',
  D = 10,
  E,
  F,
};
从A到F它们的值依次是: 0,1,'c',10,11,12
```

枚举类型的双向映射
```
emun Color{
  Red,
  Green,
  Blue,
};

Color.Red; // 0
Color[0]; // 'Red'
```

3.2 any、unknow、void、Never
any直接跳过类型检测

  const str: any = 'helo ts!';
  str = 1024;  //修改成数字类型

unkonw类型的变量可以使用其它类型赋值,但不能将unkonw类型赋值给any和unkonw以外的其它类型

let a :unknow;
a = 'str'; //ok
a = 1; //ok
a = true; //ok

let b: string = 'hello';
b = a; //not ok

void类型用作函数的返回值,表示返回值为空或无返回值

function foo():void{
 console.log('foo');
};

// 箭头函数
const bar = ():void => {
   console.log('foo');
}
  

never类型表示代码终止或死循环,即代码进入后无法走出去。如抛出异常和死循环

function error(): never{
  throw new Error('程序异常')
};

function infiniteLoop(): never{
  while(true){

  }
};

4. interface

接口是一层抽象,用来实现复杂数据的类型,具体的类型在类里面定义,可以嵌套和使用其它类型

enum Gender {
 'Male',
 'Female'
}

interface User{
 name: string,
 age: number,
 getName: ()=> string,
 accountInof:{
   account: string,
   email: string
 },
 gender: Gender
}

为对象添加任意类型的属性(不限制属性个数)

interface User{
 name: string,
 age: number,
 [_:string]: any
};

const jack: User = {
 name: 'jack',
 age: 12,
 gender: 'male',
 hobbise: ['swimming','run', 'music']
};

//任意类型的obj
interface anyObj {
 [_:string]: any
}

属性的只读和可选

interfase User{
  name ? :string,
  readOnly age: number
}

readOnly和const的区别:

  • const 是js的常量,是在js运行期间发现错误,ts的readOnly是类型的检测是在编译阶段
  • const声明的复杂类型的变量如数组和对象类型仍然可以修改数组或者对象内容,readOnly不可以

5 交叉类型 &

5.1 交叉类型的使用
交叉类型得到的是两个或多个类型的属性合集

interface A {
  a: string,
  b: number
}

interface B{
  c: boolean
}


export type C = A & B;

const t: C = {
  a: '0',
  b: 0,
  c: true,
}

当属性有冲突的时候最终得到的是属性的合集,如下面的属性a得到的是 string & number,即使字符型又是数字类型的是永远不会成立的,最后a的属性类型就是never。基础类型的冲突合并都会得到never类型。

interface A {
 a: string,
 b: number,
}

interface B{
 c: boolean
 a: number,
}

export type C = A & B;

// 等同于
export type C = {
a: never,
b: number,
c: boolean
}

当interface中具有未知类型的属性时,在使用交叉类型合并的时候要格外小心,以防得到never类型。

5.2 type和interface的异同
相同点:1. type和interface都可以用来表示对象和函数类型 2.type和interface都可以实现继承

不同点:

  • type还可以使用基础类型和其他类型
  • type可以使用操作符进行计算如交叉&类型
  • type可以使用函数和表达式
  • type通过 & 实现继承 , interface通过extends关键字继承
  • 多个同名的interface会自动合并, type同名会报错
interface A {
  a: string,
  b: number,
}

interface B{
  c: boolean
  a: number,
}

export type C = A & B;

type D = string;
type E = A
type F = A & B;
type G = () => A | B;
type I = {
  name: string
  getName: () => string
}

同名的interface会自动合并

interface A{
  a: string,
}

interface A{
  b: boolean,
}

interface A{
  c: number,
}

const a:A = {
  a: 'str',
  b: true,
  c: 0
};

总结来说type的范围比interface要大,而且更加灵活可以使用各种类型、交叉类型、函数和表达式的计算

6. 类型断言

我们在写js代码的时候,有些场景ts无法推断出变量的类型,这个时候就需要使用断言去手动设置变量的类型。

// 写法一
let len = ('str' as any).length;

// 写法二
let len = (<string>str).length; //对jsx不友好,有语法问题 不建议使用

// 非空断言
let name:string = '张三';
var a: string | undefined = undefined;
name = a!;

7. 类型守卫

由于ts的类型具有多态性,在代码执行的过程中可能我们不关心它具体是哪种类型,但仍然可以通过对属性或者类型的判断确定某种类型的具体类型。

interface Man{
  name: string,
  age: number,
  gender: 'male',
}

interface Women{
  name: string,
  age: number,
  gender: 'female',
}

type Person =  Man | Women;
const p1: Man = {
  name:'jack',
  age:21,
  gender:'male',
}
function getGender(p:Person){
  if(p.gender==='male'){
    console.log('是Man类型');
  }else{
    console.log('是Women类型');
  }
};

8. 函数重载

  class Person{
    getUserInfo(name:string,age:string):  string;
    getUserInfo(name:number,age:string):  string;
    getUserInfo(name:string,age:number):  string;
    getUserInfo(name:number,age:number):  number;
    getUserInfo(name: number | string, age: string | number):  string | number{
      if(typeof name ==='string' && typeof age ==='string'){
        return name + age;
      }
      return name;
    }
  }

declare 的函数重载

declare function test(para: User): number;
declare function test(para: number, flag: boolean): number

9. 泛型

泛型就将类型作为参数传递,具体的类型在使用的时候才确定,可以同时支持多种数据类型

function add<T,U>(x:T,y:U):T | U{
  return x + y;
}

//使用
const rs = add<String,Number>('1',2);
console.log(rs);

10. 装饰器

装饰器之前的文章之前介绍过了,具体可参考:ES6类和装饰器的使用总结

11. 总结

  1. TypeSecript是JavScript的超集,提供了类型检测功能,ts的类型检测是在编译阶段。TypeScript适用于复杂的大型协作项目,提升开发效率和降低代码维护成本。
  2. typeScript提供了numbe、string、boolean、undefined、null的基础类型,数组的类型有两种表示方式,还可以使用元组表示具有多种数据类型的数组。对象类型用interface定义,Object.proptotype的属性使用ts提供的Object类型。
  3. 枚举类型提供了一种散列映射的功能,而且是双向映射,需要注意异构的value的值。
  4. any、unknow、void、never的区别。any直接绕过类型检测,unknow类型的变量可以被赋值其它类型,但不能赋值给any和unknow以外的类型,void用作函数的返回值表示无返回值或返回值为空,never表示代码停止运行、进入死循环、类型用域不成存在(string & number)。
  5. interfcace和type的异同
    相同点是interface和type都可以表示对象和函数类型,而且都能实现继承功能。区别是:
    • interface只能表示对象和函数类型,而type可以表示基础类型和其它任意类型,而且可以使用操作符和表达式进行计算。
    • 同名的interface声明多个会自动合并,type则不能存在同名的类型声明
    • 3.interface通过extends关键字实现继承,type通过交叉类型实现继承
  6. 使用as进行类型的断言,非空断言
  7. 类型守卫: 由于ts类型具有多态性,代码执行的时候我们并不关心具体是哪种类型,但仍然可以通过属性类型进行判断
  8. 泛型就是将类型当作函数参数传递,具体到函数执行的时候才确定类型,能同时支持多种数据类型
  9. 函数重载能同时定义多个函数类型,根据传入的参数去决定具体使用的是哪一个
  10. 装饰器能对类和属性进行包装和处理,是前端AOP的一种方案