类型挑战

本文案例来自type-challenges

面试题

connected

该题是 lettCode 上面一道经典题目 题目链接

问题定义

假设有一个叫 EffectModule 的类

class EffectModule {}

这个对象上的方法只可能有两种类型签名:

interface Action<T> {
payload?: T
type: string
}
asyncMethod<T, U>(input: Promise<T>): Promise<Action<U>>
syncMethod<T, U>(action: Action<T>): Action<U>

这个对象上还可能有一些任意的非函数属性

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',
};
}
}

现在有一个叫 connect 的函数,它接受 EffectModule 实例,将它变成另一个对象,这个对象上只有EffectModule 的同名方法,但是方法的类型签名被改变了:

asyncMethod<T, U>(input: Promise<T>): Promise<Action<U>> 变成了
asyncMethod<T, U>(input: T): Action<U>
syncMethod<T, U>(action: Action<T>): Action<U> 变成了
syncMethod<T, U>(action: T): Action<U>

例子:

EffectModule 定义如下:

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',
};
}
}

connect 之后:

// 修改 Connect 的类型,让 connected 的类型变成预期的类型
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>;
};
const effectModule = new EffectModule();
const connected: Connected = connect(effectModule);

要求

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

实现

展开source面板 查看答案✌️