我也来记录一下一道typescript网红题目

301 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

🥑 题目要求

原题地址: github.com/LeetCode-Op…

要求有一个 type Connect = (module: EffectModule) => anyany 替换成题目的解答,让编译能够顺利通过

interface Action<T> {
  payload?: T;
  type: string;
}

class EffectModule {
  count = 1;
  message = 'hello!';

  delay(input: Promise<number>) {
    return input.then(i => ({
      payload: `hello ${i}!`,
      type: 'delay',
    }));
  }

  setMessage(action: Action<Date>) {
    return {
      payload: action.payload!.getMilliseconds(),
      type: 'set-message',
    };
  }
}

// 修改这里的any使得能够编译通过
type Connect = (module: EffectModule) => any;

const connect: Connect = m => ({
  delay: (input: number) => ({
    type: 'delay',
    payload: `hello 2`,
  }),
  setMessage: (input: Date) => ({
    type: 'set-message',
    payload: input.getMilliseconds(),
  }),
});
type Connected = {
  delay(input: number): Action<string>;
  setMessage(action: Date): Action<number>;
};

export const connected: Connected = connect(new EffectModule());

🥑 我个人的解法

type FuncReturnTypes<T> = ReturnType<T[keyof T]>;
type UnAction<T> = T extends Action<infer P> ? P : T;
type UnPromise<T> = T extends Promise<infer P> ? P : T;
type UnActionAndUnPromise<T> = UnAction<UnPromise<T>>;
type UnActionAndUnPromiseFunc<T, U> = T extends (
  args: infer P,
) => FuncReturnTypes<U>
  ? UnActionAndUnPromise<P>
  : T;

type FuncName<T> = {
  [P in keyof T]: T[P] extends Function ? P : never;
}[keyof T];

type MapReturnType<T> = T extends infer P
  ? P extends number
    ? string
    : number
  : never;

type ReturnType<T> = T extends (...args: any[]) => infer P ? P : never;

type Connect = (module: EffectModule) => {
  [T in FuncName<EffectModule>]: (
    args: UnActionAndUnPromiseFunc<EffectModule[T], EffectModule>,
  ) => Action<
    MapReturnType<UnActionAndUnPromiseFunc<EffectModule[T], EffectModule>>
  >;
};

🥑 网上更好的解法

cloud.tencent.com/developer/a…

type FunctionKeys<T> = { [k in keyof T]: T[k] extends Function ? k : never }[keyof T]
type functionKeys = Pick<EffectModule, FunctionKeys<EffectModule>>

type UnPromisify<T> = T extends Promise<infer U> ? U : T
type UnAction<T> = T extends Action<infer U> ? U : T

type MapTypeToUnPromisifyAndUnAction<T extends any[]> = {
  [k in keyof T]: UnAction<UnPromisify<T[k]>>
}

type Connect = (module: EffectModule) => ({
  [functionKey in keyof functionKeys]: (input: MapTypeToUnPromisifyAndUnAction<
    Parameters<functionKeys[functionKey]>
    >[number]) => UnPromisify<ReturnType<functionKeys[functionKey]>>
})