添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
logo
登录 / 注册

TypeScript在项目中的实践总结

头像
好未来技术
2022-04-28 · 好未来技术


导读: ts类型使用示例,各类型层级、特点及应用场景总结;类型守卫及方式;泛型、泛型工具函数介绍工具函数的实现。


1

Why use

  • 供静态类型检查,可以尽早检出程序错误,降低bug率、增加代码健壮性;

  • 丰富的类型系统并提供最新和不断发展的 JavScript 特性,让代码更简洁、高效;

  • 完善的生态支持,@types、eslint、IDE、tsc/babel编译器等,方便从js迁移到ts及ts的高效接入;

  • 配合编辑器的代码提示,提升编码效率;







2

基础介绍

基础类型

http://www.tslang.cn/docs/handbook/basic-types.html
boolean、number、string、数组、元组、枚举、any、Void、Null、Undefined、Unknown、Never


类型使用示例:

let isDone: boolean = false;let decLiteral: number = 6;let name: string = "bob”;let list: number[] = [1, 2, 3];let list: Array<number> = [1, 2, 3]; let fn = (a: string): void => {}
// 元组let x: [string, number]; 
x = ['hello', 10]; // OK x = [10, 'hello']; // Error
// 枚举-数字枚举默认从0开始 自增1enum GENDER { MALE = 1, FEMALE }// 性别const genderList = [    { label: '全部', value: '' },    { label: '男', value: GENDER.MALE },    { label: '女', value: GENDER.FEMALE }]console.log(GENDER[2])
// anylet notSure: any = 4; notSure.ifItExists(); // okay, ifItExists might exist at runtimenotSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check)



TS中的关键字及各种符号

Interface、type、extend、readonly、as、<>、!、&、|、:、typeof、keyof


使用示例:

// type、interfacetype INumorStr = number | stringtype IButtonType = 'default' | 'success' | 'danger' | 'warning' | ‘text' 
interface IPageParams { offset: number; readonly pageSize: number;}/** 用户列表搜索参数, * 写在这个多行注释块中的内容可以在引用的地方被看到 */interface IUserSearchParams { /** 用户靓号ID 这里的注释内容也可以在引用的地方被看到 */ beautyId?: string; /** 用户昵称 */ nickname?: string; status?: number | string; gender?: number | string; registDate: [string, string]; lastLoginDate: [string, string];} & IPageParams
// Readonly 将接口IUserSearchParams的属性变只读const searchParamsTpl: Readonly<IUserSearchParams> = { beautyId: '', nickname: '', status: '', gender: '', registDate: ['', ''], lastLoginDate: ['', ''], offset: 0, pageSize: 30} /** * 定义动态接口 * 主要应用场景:服务端返回内容肯能有多余属性* 可以把前端需要的定义成必要属性,其他包含在动态属性里* /interface IIdMust { id: number [k: string]: any }
// extends =》抽离两个接口的公共部分实现共用interface IConditionData {    platId: string;    appId: string;    secretKey: string;    payType: number;}export interface IWxConditionData extends IConditionData {    wxBusinessNo: string;}export interface IZfbConditionData extends IConditionData {    publicKey: string;}
// as、<>、!// 当你了解传入参数更具体的类型时,类型断言能按预期工作:let someValue: any = "this is a string";let strLength: number = (<string>someValue).length; let someValue: any = "this is a string";let strLength: number = (someValue as string).length; // 当原始类型 和 目标类型 中的任何一个都不能赋值给另外一个时可以通过先断言成any再断言成目标类型function handler(event: Event) {  const element = (event as any) as HTMLElement; // ok}
// typeofconst vT11 = {    a: 1,    b: 'ssss',    c: false}type T11 = typeof vT11const conditionData: T11 = {    a: 2,    b: 'here are some words',    c: true}
// keyofinterface IConditionData {    platId: string;    appId: string;    secretKey: string;    payType: number;}type IPartial<T> = {    [key in keyof T]?: T[key]}type IConditionDataPartial = IPartial<IConditionData>



各种类型的特点及应用场景总结

  • boolean、number、string、Null、Undefined描述一个对应类型的数据

  • tuple:描述固定长度、固定位置固定类型的数据

  • 枚举:描述mapping关系

  • interface: 描述一组数据 是开放式的 重复定义不会覆盖会叠加

  • void: 对应函数没有返回值时对返回值的描述

  • any: 顶层类型,不受约束、编译时跳过类型检查可以进行任何操作(不推荐使用)

  • unknown:顶层类型,所有类型都可以分配给unknown,手动判断类型(断言)后才能操做

  • never:底层类型,用于永远不可能发生的情况,除了never本身 不能将任何类型赋值给never, 主要用于错误检查


// interface// lib.es2017.string.d.tsinterface String {    padStart(maxLength: number, fillString?: string): string;    padEnd(maxLength: number, fillString?: string): string;}// lib.es2019.string.d.tsinterface String {    padStart(maxLength: number, fillString?: string): string;    padEnd(maxLength: number, fillString?: string): string;}
/** Removes the trailing white space and line terminator characters from a string. */trimEnd(): string; /** Removes the leading white space and line terminator characters from a string. */trimStart(): string; /** Removes the leading white space and line terminator characters from a string. */trimLeft(): string; /** Removes the trailing white space and line terminator characters from a string. */trimRight(): string;
// nevertype T9 = number | string | booleanconst fnNeverUse = (param: T9): number => {    if (typeof param === 'string') {        return param.length    } else if (typeof param === 'number') {        return param    } else if (typeof param === 'boolean') {        return 1    } else {        const vNever: never = param    }} const fnNeverUse = (param: T9): number => {    if (typeof param === 'string') {        return param.length    } else if (typeof param === 'number') {        return param    } else {        const vNever: never = param // 不能将类型“boolean”分配给类型“never”。ts(2322)    }}
// unknownlet vT10: unknownvT10 = 10vT10.toFixed(2) // 类型“unknown”上不存在属性“toFixed”。(vT10 as number).toFixed(2)



通过extends看类型层级

该块内容参考:

http://zhuanlan.zhihu.com/p/472894788

Top Type 与 Bottom Type ,示例写法直观,故引用参考,感谢作者。

never(底层类型)< 字面量类型(‘abc’、123) < 原始类型(string、number) < any、unknown( 顶层类型)
type T1 = never extends 'abc' ? 1: 2type T2 = 'abc' extends string ? 3: 4type T3 = string extends Object ? 5: 6type T4 = Object extends any ? 7: 8type T5 = Object extends unknown ? 9: 10type T6 = any extends unknown ? 11: 12type T7 = unknown extends any ? 13: 14 
type T8 = never extends 123    ? 123 extends number        ? number extends Object            ? Object extends any                ? any extends unknown                    ? unknown extends any                        ? 11 : 13                    : 9                : 7            : 5        : 3      : 1 


3

类型守卫

TS 会在语句的块级作用域内「收紧」变量的类型的推断行为称作类型守卫 (Type Guard)。


  • Is关键字-用户自定义的类型保护

  • 查找类型

  • In

  • Typeof/keyof/instanceof

  • Typeof 获取js对象所定义的类型

  • keyof 获取interface的键(用键组成联合类型、批量转换类型)

  • 字面量相等判断


// isinterface IUserChartDataItem {key: 'user',  newPlayerCount: number;  dauCount: number;  rechargeCount?: number;  dayDate: string;}
interface IFinChartDataItem {key: 'fin', rechargeCount: number; rechargeAmount: number; dayDate: string;}const isUserChartDataItem = (item: IUserChartDataItem | IFinChartDataItem): item is IUserChartDataItem => !!((item as IUserChartDataItem).key === 'user')
// ininterface Foo {  foo: string;}interface Bar {  bar: string;}function test(obj: Foo | Bar) {  if ('foo' in obj) {    // 对象obj的类型通过in判断专属属性是否存在「收紧」为 Foo  } else {    // 对象obj「收紧」为 Bar  }}
// typeoffunction test(input: string | number) {  if (typeof input === 'string') {    // 通过判断input的类型「收紧」为 string  } else {    // number  }}
// instanceofclass Foo {}class Bar {}function test(input: Foo | Bar) {  if (input instanceof Foo) {    // input「收紧」为 Foo  } else {    // input 的类型「收紧」为 Bar  }}
// 字面量相等判断type Foo = 'foo' | 'bar' | 'others';function test(input: Foo) {  if (input !== 'others') {    // input 的类型「收紧」为 'foo' | 'bar'  } else {    // input 的类型「收紧」为 'others'  }}



4

泛型及泛型工具函数

泛型

泛型是指在定义接口、函数或类时,不预先指定具体的类型,而是在使用的时候 再指定类型限制的一种类型定义


// 泛型限制接口字段类型interface IInterfaceT<T> {    nickname: T;    address: T;}
const T13: IInterfaceT<string> = { nickname: 'Nate', address: 'BJ'}
// 泛型限制函数参数及返回值类型function test<T>(name: T): T{  return name}test<number>(123) // 返回值为number//定义多个类型test<number|string>(123) //  返回值为number
// 泛型限制构造函数参数类型以及类成员变量、方法参数的类型class Animal <T>{        name: T    constructor(name: T){        this.name = name    }    action(say: T): T{        return say    }}let dog = new Animal<string>('旺财')dog.action(123) // 类型“number”的参数不能赋给类型“string”的参数。ts(2345)
// 泛型限制构造函数参数类型以及类成员变量、方法参数的类型class  Animal <T>{      name: T  constructor(name: T){    this.name = name  }  action<T>(say: T): T{    return say  }}let dog = new Animal<string>('旺财')dog.action<string>('汪汪汪')  dog.action<number>(123)



泛型工具函数

http://www.typescriptlang.org/docs/handbook/utility-types.html#partialt


  • Partial: 定义一个新类型是类型Type的任意部分=》也就是把Type里定义的属性都变成可选属性

  • Required:定义一个新类型把类型Type中的可选属性也变成必需属性

  • Readonly:定义一个新类型把类型Type中的所有属性都变成只读属性

  • Record:定义一个新类型键为keys对应的一组值, 每个key对应的类型为Type

  • Pick:取接口Type中keys中各键以及键对应的类型组成新的接口

  • Omit:删除接口Type中keys中键组成新的接口

  • Exclude:删除联合类型UnionType中包含在ExcludedMembers中的类型组成新的类型

  • Extract:找出Type和Union中一共有的类型组成新的类型

  • NonNullable:去除联合类型Type中的null和undefined

  • Parameters:获取函数类型Type中的参数类型组成tuple

  • ReturnType:返回函数类型Type中的返回值类型作为新的类型


// Partial实现interface IConditionData {    platId: string;    appId: string;    secretKey: string;    payType: number;}type IPartial<T> = {    [key in keyof T]?: T[key]}type IConditionDataPartial = IPartial<IConditionData>
// Exclude 实现type IExclude<T, U> = T extends U ? never : T
// Extract 实现type IExtract<T, U> = T extends U ? T : never 
// Pick 实现interface IConditionData {    platId: string;    appId: string;    secretKey: string;    payType: number;}type IPick<T, K extends keyof T> = {    [key in K]: T[key]}type IConditionDataPick = IPick<IConditionData, 'appId' | 'platId'>


string 字段 typeof
阅读 4
声明:本文内容由脉脉用户自发贡献,部分内容可能整编自互联网,版权归原作者所有,脉脉不拥有其著作权,亦不承担相应法律责任。如果您发现有涉嫌抄袭的内容,请发邮件至[email protected],一经查实,将立刻删除涉嫌侵权内容。