V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
a132811
V2EX  ›  TypeScript

ts 如何根据可选参数返回不同的泛型成员,有简单的写法吗?

  •  
  •   a132811 · 2022-09-14 22:21:52 +08:00 · 1360 次点击
    这是一个创建于 561 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我想实现一个 ts 版本的简版 usePromise

      // 期望类型推导出:data 的类型是 {list: FileNode[]} (即返回 T)
      const [data, isOk] = usePromise(
        () => {
          return Promise.resolve({list:[]}) as Promise<{ list: FileNode[] }>;
        },
        { initValue: {list:[]} }
      );
    
      // 期望类型推导出:fileNodes 的类型是一个 FileNode 数组 (即返回 T['list'])
      const [fileNodes, isOk] = usePromise(
        () => {
          return Promise.resolve({list:[]}) as Promise<{ list: FileNode[] }>;
        },
        { initValue: [] },
        "list",
      );
      
    
    

    我的 usePromise 实现如下, 利用K extends keyof T 判断如果 K 属性存在就返回T[K], 否则返回T 测试发现 ts 判断可选参数时总会失败,只会返回T.

    export function usePromise<T, K>(
      factory: () => Promise<T>,
      options: Options<K extends keyof T ? T[K] : T> = {},
      filterKey?: K,
    ): [K extends keyof T ? T[K] : T, boolean] {
      type R = K extends keyof T ? T[K] : T;
      const [state, setState] = useState<R>(
        options.initValue!,
      );
      const isLoadingRef = useRef(false);
      useEffect(() => {
        factory().then((r) => {
          if (filterKey) {
            setState((r as any)[filterKey] as unknown as R);
          } else {
            setState(r as unknown as R);
          }
        }).catch((res) => {
          if (options.onError) options.onError(res);
          else throw res;
        });
      }, []);
      return [state, isLoadingRef.current] as [R, boolean];
    }
    
    
    

    我知道可以增加两个 function 的类型重载解决这个问题,但是手写一遍类型重载感觉太麻烦。

    请教一下有没有更简单的方法呢?

    3 条回复    2022-09-15 11:55:17 +08:00
    a132811
        3
    a132811  
    OP
       2022-09-15 11:55:17 +08:00
    @YuJianrong 不是纠结范型。只是想找一个比 overloaded 更简单的方法。

    在 statckoverflow 我找到答案啦:
    https://stackoverflow.com/questions/73718892/return-different-generic-type-via-functions-optional-argument-in-typescript
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5863 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 01:58 · PVG 09:58 · LAX 18:58 · JFK 21:58
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.