在Typescript中如何优雅的使用provide/inject

647 阅读1分钟

provide/inject是vue中实现父组件与后代组件共享数据的方式,但是在typescript中直接使用provide/inject,会丢失共享的数据类型。如下所示:

父组件中使用

image.png

子组件中使用

image.png

这里分享一个自定义方法,实现provide/inject类型声明

首先通过一个工具函数封装provide和inject

image.png

返回值解构出来的createProjectInfouseProjectInfo相当于封装了我们指定业务数据的provide/inject

父组件中使用

image.png

子组件中使用

image.png

可以看到使用useProjectInfo就能够返回我们需要的数据的类型

createContextHook使用说明

createContextHook(key, func)

  • 函数接收key,func两个入参,返回 {createXxx, useXxx}对象
  • 第一个参数Key,同provide/inject一样,且作为返回值中Xxx的对应的命名
  • 第二个参数func,其返回结果作为provide的第二个参数,inject的返回值
  • createXxx其实就是包装func,并func的返回值存入provide中
  • useXxx就是对inject(key)的包装

这种方式可以使我们共享数据的定义非常灵活,且充分利用了ts类型推导的能力,不用手动去声明类型了

createContextHook源码

export function createContextHook<
  TKey extends Capitalize<string>,
  TCreateFunc extends (...args: any) => any
>(key: TKey, createFunc: TCreateFunc) {
  const symbolKey = Symbol(key);

  function create(...args: any[]) {
    const obj = createFunc(...args);
    provide(symbolKey, obj);
    return obj;
  }

  function use() {
    return inject(symbolKey);
  }

  return {
    [`create${key}`]: create,
    [`use${key}`]: use,
  } as {
    [name in `create${TKey}`]: TCreateFunc;
  } & {
    [name in `use${TKey}`]: () => ReturnType<TCreateFunc>;
  };
}

可以看到源码其实很简单,主要是运用了typescript的类型声明的一些能力

感兴趣的小伙伴,可以自己试一试,希望本文对你在ts中使用provide/inject有所帮助!