Mike-Zhu / note

note
3 stars 1 forks source link

TypeScript 题 #10

Open Mike-Zhu opened 4 years ago

Mike-Zhu commented 4 years ago

TypeScript 题

/* eslint-disable import/prefer-default-export */
/* eslint-disable class-methods-use-this */
import { expect } from 'chai';

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

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

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',
    };
  }
}
type ParamType<T extends (input: any) => any> = T extends (input: infer P) => any ? P : T;
type UnPromise<T> = T extends Promise<infer P> ? P : T;
type UnWrap<T> = T extends Action<infer U> ? U : Unpromise<T>;

// 修改 Connect 的类型,让 connected 的类型变成预期的类型
type Connect = (module: EffectModule) => {
  [T in FuncName<EffectModule>]: (param: UnWrap<ParamType<EffectModule[T]>>) => UnPromise<ReturnType<EffectModule[T]>>
};

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());