一篇够用的TypeScript总结【实用】

共 7712字,需浏览 16分钟

 ·

2021-09-11 11:43

一、前言

鬼哥今天给大家分享的这篇文章来自,有赞@俊劫大佬的一篇总结文章,在坐地铁的时候,花个10分钟碎片时间来学习下,还是非常有必要的,还是非常有收获的一篇文章。

没写ts之前看官方文档 (opens new window),被那么多特性吓尿了,实际上写业务用的特性不多。

这里更多的是,以自己的理解去总结一下常用的ts特性。总结一些项目中使用较多的,一些TS高级特性·关注公众号,后面会持续ts系列的文章的

二、ts类型

本篇所有demo都可在TypeScript Playground (opens new window)运行,不理解的建议都来跑跑看。

1、基础类型

  • 常用:
booleannumberstring、array、enumanyvoid
  • 不常用:
tuple、null、undefine、never

2、对象类型

简单理解interfacetype 的区别:type 更强大,interface 可以进行声明合并,type 不行;

看个人习惯,一般声明都用interface,需要用到其他变量类型,type多一些。有没有interfacetype一把梭的🤣?

interface Hero {
  name: string;
  age: number;
  skill: string;
  skinNum?: number;
  say(): string// say函数返回值为string
  [propname: string]: any// 当前Hero可定义任意字符串类型的key
}
// 继承
interface littleSoldier extends Hero {
  rush(): string;
}
// 任意类型
interface IAnyObject {
  [key: string]: any;
}

type Hero = {
  name: string,
  age: number,
  skill: string,
  skinNum?: number,
};

3、数组类型

项目中常见的写法,需要声明列表数据类型:

interface IItem {
  id: number;
  name: string;
  isDad: boolean;
}
const objectArr: IItem[] = [
  { id: 1, name: '俊劫', isGod: true }
];

// or
const objectArr: Array<IItem> = [
  { id: 1, name: '俊劫', isGod: true }
];

const numberArr: number[] = [123];

const arr: (number | string)[] = [1"string"2];

4、元组 tuple

  • 元组和数组类似,但是类型注解时会不一样

  • 赋值的类型、位置、个数需要和定义(生明)的类型、位置、个数一致。

  • 暂时没用过,感觉用处不大~~~

  • 数组 某个位置的值可以是注解中的任何一个

const LOL: (string | number)[] = ["zed"25"darts"];

// 元祖 每一项数据类型必须一致
const LOL: [stringstringnumber] = ["zed""darts"25];

5、联合| or 交叉&类型

  • 联合类型:某个变量可能是多个 interface 中的其中一个,用 | 分割
  • 交叉类型:由多个类型组成,用 & 连接
// anjiao 某胖博主爱好
interface Waiter {
  anjiao: boolean;
  say: () => {};
}

interface Teacher {
  anjiao: boolean;
  skill: () => {};
}

// 联合类型
function judgeWho(animal: Waiter | Teacher{}
// 交叉类型 
// 同名类型会进行合并,同名基础类型属性的合并返回:never
// 同名非基础类型属性可以正常合并
function judgeWho(jishi: Waiter & Teacher{}

6、enum枚举

提高代码可维护性,统一维护某些枚举值,避免 JiShi === 1这种魔法数字。JiShi === JiShiEnum.BLUEJ这样写,老板一眼就知道我想找谁。

// 初始值默认为 0
enum JiShiEnum {
     REDJ,
     BLUEJ,
     GREENJ,
}
// 设置初始值
enum JiShiEnum {
     REDJ = 8,
     BLUEJ,
     GREENJ,
}
const jishi: JiShiEnum = JiShiENUM.BLUE
console.log(jishi) // 9
// 字符串枚举,每个都需要声明
enum JiShiEnum {
     REDJ = "8号",
     BLUEJ = "9号",
     GREENJ = "10号",
}

7、泛型 T(Type)

简单说就是:泛指的类型,不确定的类型,可以理解为一个占位符(使用T只是习惯,使用任何字母都行)

  • K(Key):表示对象中的键类型;
  • V(Value):表示对象中的值类型;
  • E(Element):表示元素类型。
// T 自定义名称
function myFun<T>(params: T[]{
  return params;
}
myFun <string> ["123""456"];

// 定义多个泛型
function join<TP>(first: T, second: P{
  return `${first}${second}`;
}
join <numberstring> (1"2");

8、断言

主要通过 as 语法,告诉ts这个变量属于哪个类型,一般用在你比 TypeScript 更了解某个值的详细信息。

function judgeWho(animal: Waiter | Teacher{
  if (animal.anjiao) {
    (animal as Teacher).skill();
  }else{
    (animal as Waiter).say();
  }
}

9、in

类似于数组和字符串的 includes 方法

function judgeWhoTwo(animal: Waiter | Teacher{
  if ("skill" in animal) {
    animal.skill();
  } else {
    animal.say();
  }
}

10、类型注解

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

let count: number// 类型注解
count = 123;

11、类型推断

  • 如果 TS 能够自动分析变量类型, 我们就什么也不需要做了
  • 如果 TS 无法分析变量类型的话, 我们就需要使用类型注解
// ts可以推断出count 为number类型
let count = 123;

12、void和never

返回值类型,也算是基础类型。没有返回值的函数: void

function sayHello(): void {
  console.log("hello world");
}

如果一个函数是永远也执行不完的,就可以定义返回值为 never

function errorFuntion(): never {
  throw new Error();
  console.log("Hello World");
}

一个函数有入参,也有出参,项目中的常规写法:

// 定义一个小姐姐
interface IGirl {
  name: string,
  age: number,
  skill: string,
  isAnMo: boolean;
  number: JiShiEnum;
};
// 定义搜索小姐姐的入参
interface ISearchParams extends IGirl{
  serviceTime: string;
}
interface IGetGirls {
  data: IGirl[];
}
// 函数主体
export function getGirls(data: ISearchParams): Promise<IGetGirls{
  return axios({
    url: `/dabaojian/getGirls`,
    method: 'GET',
    data,
  });
}

13、类型检测

1、typeof

typeof 操作符可以用来获取一个变量或对象的类型

interface Hero {
  name: string;
  skill: string;
}

const zed: Hero = { name: "影流之主", skill: "影子" };
type LOL = typeof zed; // type LOL = Hero

在上面代码中,我们通过 typeof 操作符获取 zed 变量的类型并赋值给 LOL 类型变量,之后我们就可以使用 LOL 类型

const ahri: LOL = { name: "阿狸", skill: "魅惑" };

2、instanceof

class NumberObj {
  count: number;
}
function addObj(first: object | NumberObj, second: object | NumberObj{
  if (first instanceof NumberObj && second instanceof NumberObj) {
    return first.count + second.count;
  }
  return 0;
}

3、keyof

keyof 与 Object.keys 略有相似,只不过 keyof 取 interface 的键

interface Point {
    x: number;
    y: number;
}

// type keys = "x" | "y"
type keys = keyof Point;

用 keyof 可以更好的定义数据类型

function get<T extends objectK extends keyof T>(o: T, name: K): T[K{
  return o[name]
}

14、ts类里的关键字

了解ts关键字的作用,在写base类的时候可能会用到,个人用的不多。

  • public
  • private 类的外部不可用,继承也不行
  • protected 类的外部不可用,继承可以
  • public readOnly xxx 只读属性
  • static funcXXX 静态方法,不需要 new 就可以调用
  • abstract funcXXX 抽象类,所有子类都必须要实现 funcXXX

二、ts的优缺点

优点

代码的可读性和可维护性:举个🌰看后端某个接口返回值,一般需要去network看or去看接口文档,才知道返回数据结构,而正确用了ts后,编辑器会提醒接口返回值的类型,这点相当实用。在编译阶段就发现大部分错误,避免了很多线上bug 增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等

三、anyScript

可能因为业务场景或者业务紧张,or某个跑路的大哥省了点功夫,用了typeScript的项目也可能会变成anyScript。以下是几种救急的方式:

// @ts-nocheck 禁用整个文件的ts校验
// @ts-ignore 禁用单行ts校验

anyunknown 不建议多用,但也不是不能用,有些场景确实不好写ts定义。

原文地址

https://juejin.cn/post/6981728323051192357

❤️ 看完三件事

非常棒的一篇Ts实用文章,

如果你觉得这篇内容对你挺有启发,不妨:

  • 点个【在看】,或者分享转发,让更多的人也能看到这篇内容

  • 点击↓面关注我们,一起学前端

  • 长按↓面二维码,添加鬼哥微信,一起学前端



浏览 75
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报