yehq / dva-model-enhance

修改 dva 的写法,更好的支持 typescript
21 stars 4 forks source link

Any plan on effect return types? #9

Open git9am opened 3 years ago

git9am commented 3 years ago

This project offers a way to ensure typing between Components and Models. But we still have typing issues within Models since yield ends up with an any return type, as is explained under microsoft/TypeScript#2983. E.g. in redux-saga Models we often have cases like:

const result = yield this.effects.call(fn, payload);  // <- result is any

Models plays an important role in firing API calls and gathering API responses. And since that's error-prone for data typing, it would be very helpful to make those effect calls type sensitive.

For example, we may wrap effects.call into another generator with type declaration, so that we have:

In lib/BaseModel.d.ts,

type FunctionType = (() => any) | ((...args: any) => any);
type Unpromise<T extends FunctionType> = ReturnType<T> extends Promise<infer U> ? U : ReturnType<T>; // TODO: T may extend Generator
export interface EffectsCommandMap<StoreState> extends DvaEffectsCommandMap {
    // ...
    call<F extends FunctionType>(func: F, ...args: any): Generator<Unpromise<F>, Unpromise<F>>,
    // ...
}

In src/decorators/effect.ts,

const _call = effects.call;
currentThis.effects.call = function*(func: any, ...args: any) {
    return (yield _call(func, ...args));
};

And in model files, by replacing yield with yield*,

const result = yield* this.effects.call(fn, payload);  // <- result is now the return type of fn

Will such a patch make sense to this project?

yehq commented 3 years ago

Thanks for your suggestion! You have to give it a new name like yieldCall. eg.

const _call = effects.call;
currentThis.effects.yieldCall = function*(func: any, ...args: any) {
    return (yield _call(func, ...args));
};

Maybe you can give me a PR!