TypeScript 项目开发必会技能

系列文章目录

        1.必知必会的特性

        2.枚举

        3.泛型


 

文章目录


一、必知必会的特性

 接口的作用:就是为这些类型命名和为你的代码或第三方代码定义契约

Readonly(接口)  可以声明更加严谨的可读属性,亦或者变量 

readonly vs const

最简单判断该用readonly还是const的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const,若做为属性则使用readonly

条件类型(Conditional Type)

export type DeepReadonly<T> = T extends Builtin
  ? T
  : T extends Map<infer K, infer V>
    ? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>
    : T extends ReadonlyMap<infer K, infer V>
      ? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>
      : T extends WeakMap<infer K, infer V>
          ......

其中DeepReadonly通过extends的方式继承父类然后通过? : 表达式来进行一个类型三目运算符的操作进行一个类型的条件判断。

通过一个简单的案例来进行理解,当泛型Tstring类型的时候,那么B1,反之为2。可以看到同样的一个类型,因为传入的泛型T不一样,结果自然而然的有了出入。

namespace

命名空间(namespace)是一个比较常见的东西,它常用于组织一份类型区域防止类型之间的重命名冲突,需要配置 declare 输出到外部环境才能够使用,非常便捷的在于使用declare namespace在工程项目中可以不需要引入任何类型而直接可以访问。

declare namespace JSONValue{ 
                    type:a =number;

}
const age: JSONvalue.a ='2'

declare

declare是用于声明形式存在的。

  • declare var/let/const用来声明全局的变量。
  • declare function 用来声明全局方法(函数)
  • declare class 用来声明全局类
  • declare namespace 用来声明命名空间
  • declare module 用来声明模块

 模块类型

首先,知道index.js导出是一个对象,那么declare const一个类型出来,然后通过export = config的形式对导出进行声明。那么在通过import { xxx } from '@/config就可以获悉具体的类型了。

declare const config : BaseConfig& EvnConfig 
export config 


(propety) baseApi: `http://${string}| https://${string}` from baseApi

import   {baseApi} from '@/config'

 模板字符串类型

type EventName<T extends string> = `${T}Changed`;
type T0 = EventName<'foo'>;  // 'fooChanged'
type T1 = EventName<'foo' | 'bar' | 'baz'>;  // 'fooChanged' | 'barChanged' | 'bazChanged'


type Concat<S1 extends string, S2 extends string> = `${S1}${S2}`;
type T2 = Concat<'Hello', 'World'>;  // 'HelloWorld'

 字符串模板中的联合类型会被展开后排列组合:

type T3 = `${'top' | 'bottom'}-${'left' | 'right'}`;  
// 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'

 TS 中新增了 uppercaselowercasecapitalizeuncapitalize 这些关键字,用于对模板粒度字符串变量进行处理。

type Cases<T extends string> = `${uppercase T} ${lowercase T} ${capitalize T} ${uncapitalize T}`;
type T11 = Cases<'bar'>;  // 'BAR bar Bar bar'

  配合 infer

   特别强大的一点是,模板字符串可以通过 infer 关键字,实现类似于正则匹配提取的功能:

type MatchPair<S extends string> = S extends `[${infer A},${infer B}]` ? [A, B] : unknown;
type T20 = MatchPair<'[1,2]'>;  // ['1', '2']
type T21 = MatchPair<'[foo,bar]'>;  // ['foo', 'bar']

通过 , 分割左右两边, 再在左右两边分别用一个 infer 泛型接受推断值 [${infer A},${infer B}],就可以轻松的重新组合 , 两边的字符串。

配合 ... 拓展运算符和 infer递归,甚至可以实现 Join 功能:

type Join<T extends (string | number | boolean | bigint)[], D extends string> =
    T extends [] ? '' :
    T extends [unknown] ? `${T[0]}` :
    T extends [unknown, ...infer U] ? `${T[0]}${D}${Join<U, D>}` :
    string;
type T30 = Join<[1, 2, 3, 4], '.'>;  // '1.2.3.4'
type T31 = Join<['foo', 'bar', 'baz'], '-'>;  // 'foo-bar-baz'

实现 Vuex namespace 推断:

type VuexOptions<M, N> = {
   namespace?: N,
   mutations: M,
}

type Action<M, N> = N extends string ? `${N}/${keyof M & string}` : keyof M

type Store<M, N> = {
   dispatch(action: Action<M, N>): void
}

declare function Vuex<M, N>(options: VuexOptions<M, N>): Store<M, N>

const store = Vuex({
   namespace: "cart" as const,
   mutations: {
      add() { },
      remove() { }
   }
})

store.dispatch("cart/add")
store.dispatch("cart/remove")

实现 lodash get 函数:

type PropType<T, Path extends string> =
    string extends Path ? unknown :
    Path extends keyof T ? T[Path] :
    Path extends `${infer K}.${infer R}` ? K extends keyof T ? PropType<T[K], R> : unknown :
    unknown;

declare function get<T, P extends string>(obj: T, path: P): PropType<T, P>;

const obj = { a: { b: {c: 42, d: 'hello' }}};

const value = get(obj, "a.b.c")

函数重载

函数重载是一个非常常用的特性,它大多数用于多态函数。大多数同学可能都不怎么使用。但是它能够定义不同的参数类型。需要有多个重载签名和一个实现签名

  • 重载签名:就是对参数形式的不同书写,可以定义多种模式。
  • 实现签名:对函数内部方法的具体实现。

getter/setter

get/set存取器是在class当中比较实用的一个功能,它保证了类中变量的私有化。在外部时时不能直接对其更改的,如果大家了解javaBean的话理解起来并不是很困难。

class中声明一个带_下标的变量,那么就可以通过getset对其进行设置值。

在实例中当我们调用.name的时候,其实本身就是调用了其get的方式,而设置值时,则是调用set方法,

需要注意的是,._name值也输出了,但是TypeScript会进行提示你._name是私有的不允许你访问。

 

二、枚举

枚举可以看一篇阿宝哥的小文章一文让你彻底掌握 TS 枚举

https://juejin.cn/post/6844904112669065224#heading-3

泛型

简单的函数泛型

function setSex<T> (sex: T) {
}

setSex<'男'>('女')

泛型类

class Person<T> {
    private sex: T;
    constructor(readonly type: T) { 
        this.sex = type; 
    }
}

const person = new Person<'男'>('女')

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

勒布朗-前端

请多多支持,留点爱心早餐

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值