Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于集成typescript后,models写法的疑惑 #2123

Closed
Symous opened this issue Jun 6, 2019 · 10 comments
Closed

关于集成typescript后,models写法的疑惑 #2123

Symous opened this issue Jun 6, 2019 · 10 comments

Comments

@Symous
Copy link

Symous commented Jun 6, 2019

What happens?

当我们在typescript的项目中使用dva的时候,models内的effect写法,要怎么写才能做到尽量的优雅+规范呢?比如这里有一个userModel.ts,里面的effect为:

*login({ payload, callback }, { put }) {
            // code here...
 },

假如我们的项目使用了eslint插件,这时候我们会得到错误提示,绑定元素“payload”隐式具有“any”类型。ts(7031),因为我们没有参考类型,那这里我们要如何书写相关参数的参考类型呢?payload里面的内容,我们无法确定。所以目前只能使用any,也就是:

*login({ payload, callback } : any, { put }:any) {
            // code here...
 },

有没有更好的写法呢?谢谢!

最小可复现仓库

请使用 yarn create umi 创建,选择 app,然后选上 dva,并上传到你的 GitHub 仓库

复现步骤,错误日志以及相关配置

相关环境信息

  • Umi 版本:未使用
  • Node 版本:11.2.0
  • 操作系统:macOS 10.14.5
@jinyang1994
Copy link

jinyang1994 commented Jun 11, 2019

这样不知道能不能达到你想要的效果

import { Model } from 'dva';

export default {
  name: 'test',
  state: {},
  effects: {},
} as Model;

@DiamondYuan
Copy link
Contributor

DiamondYuan commented Jun 13, 2019

What happens?

当我们在typescript的项目中使用dva的时候,models内的effect写法,要怎么写才能做到尽量的优雅+规范呢?比如这里有一个userModel.ts,里面的effect为:

*login({ payload, callback }, { put }) {
            // code here...
 },

假如我们的项目使用了eslint插件,这时候我们会得到错误提示,绑定元素“payload”隐式具有“any”类型。ts(7031),因为我们没有参考类型,那这里我们要如何书写相关参数的参考类型呢?payload里面的内容,我们无法确定。所以目前只能使用any,也就是:

*login({ payload, callback } : any, { put }:any) {
            // code here...
 },

有没有更好的写法呢?谢谢!

最小可复现仓库

请使用 yarn create umi 创建,选择 app,然后选上 dva,并上传到你的 GitHub 仓库

复现步骤,错误日志以及相关配置

相关环境信息

  • Umi 版本:未使用
  • Node 版本:11.2.0
  • 操作系统:macOS 10.14.5

你可以试试看我写的库

https://github.com/DiamondYuan/dva-model-creator

可以做到每一个 action 每一个 model 的类型都是完备的。而且和现有的 dva 完全兼容。
我已经用在生产环境了。

demo 地址

https://github.com/umijs/umi-examples/tree/master/typescript

https://github.com/DiamondYuan/vanaheim

@Symous
Copy link
Author

Symous commented Jun 15, 2019

@jinyang1994 我这边使用的时dva-core和dva-loading,没有使用dva全套,这样的话应该如何

import { Model } from 'dva';

再者想了解一下,这个as Model的用意是什么?谢谢。

@jinyang1994
Copy link

as是类型断言

@jinyang1994
Copy link

dva-core 不行的话可以只用dva的types

@Symous
Copy link
Author

Symous commented Jun 17, 2019

@jinyang1994
我从dva的声明文件index.d.ts和issue中一些相关问题中参考抽取出来了一个Model.ts作为一个类型,在models中使用,具体如下:

/* eslint-disable no-unused-vars */
import { ReducersMapObject, Reducer, Dispatch, AnyAction, Action } from 'redux';

export interface EffectsCommandMap {
    put: <A extends Action>(action: A) => any;
    call: Function;
    select: Function;
    take: Function;
    cancel: Function;
    [key: string]: any;
}
export interface EffectsMapObject {
    [key: string]: Effect | EffectWithType;
}
export interface ReducerEnhancer {
    (reducer: Reducer<any>): void;
    [key: string]: Reducer;
}
export interface SubscriptionAPI {
    dispatch: Dispatch<any>;
}
// export type ActionWithPayload = { action: Action; payload: any };
export type Effect = (action: AnyAction, effects: EffectsCommandMap) => void;
export type EffectType = 'takeEvery' | 'takeLatest' | 'watcher' | 'throttle';
export type EffectWithType = [Effect, { type: EffectType }];

export type ReducersMapObjectWithEnhancer = [ReducersMapObject, ReducerEnhancer];
export type Subscription = (api: SubscriptionAPI, done: Function) => void;
export interface SubscriptionsMapObject {
    [key: string]: Subscription;
}
export default interface Model {
    namespace: string;
    state?: any;
    reducers?: ReducersMapObject | ReducersMapObjectWithEnhancer;
    effects?: EffectsMapObject;
    subscriptions?: SubscriptionsMapObject;
}

配合断言(as Model),现在effects中的相关类型都已正确解析,唯独reducers中的传递的payload参数仍然无法解析,编辑器vscode报错为:类型“Action”上不存在属性“payload”

import Model from '@/utils/dva/Model';

export default {
    namespace: 'userModel',

    state: {
        status: 'logout',
        currentUser: '',
    },

    effects: {
        *login({ payload, callback }, { put }) {
            // ...
        },
    },
    reducers: {
        //这里的payload类型判断失败,报错为类型“Action<any>”上不存在属性“payload”。
        changeLoginStatus(state, { payload }) {  
            return {
                ...state,
                // ....
            };
        },
    },
} as Model;

请问这边哪里做的还有问题?谢谢!

@capdiem
Copy link

capdiem commented Jun 29, 2019

用这个吧 dva-model-creator

@fwh1990
Copy link

fwh1990 commented Jul 6, 2019

这个redux框架完美支持ts,拥有100%的代码提示: redux-model-ts

@Symous
Copy link
Author

Symous commented Jul 8, 2019

感谢楼上各位老哥的推荐,但是作为一个ts初学者还是想尽量自己手撸。经过我后期的实践,发现像我之前的解决方案摘出dva的Model,然后配合断言是可以实现的。唯一的问题是,在Redux升级到V4后,他的ReducersMapObject做了改变,所以我从Redux V3里面找到了相关的源代码对Model进行了改造,实测好用,分享给有缘人:

/* eslint-disable no-unused-vars */
import { ReducersMapObject, Reducer, Dispatch, AnyAction, Action } from 'redux';

export interface EffectsCommandMap {
    put: <A extends Action>(action: A) => any;
    call: Function;
    select: Function;
    take: Function;
    cancel: Function;
    [key: string]: any;
}
// export type ActionWithPayload = { action: Action; payload: any; callback: Function };
export type Effect = (action: AnyAction, effects: EffectsCommandMap) => void;
export type EffectType = 'takeEvery' | 'takeLatest' | 'watcher' | 'throttle';
export type EffectWithType = [Effect, { type: EffectType }];
export interface EffectsMapObject {
    [key: string]: Effect | EffectWithType;
}

export interface ReducerEnhancer {
    (reducer: Reducer<any>): void;
}

// 使用redux-v4.x的ReducerMapObject会导致dva reducer中的action payload等参数无法确定类型(dva中使用的是3.x的redux)
// 这里从redux v3.x中找到了对应的ReducersMapObject以解决上述问题
export interface ReduxV3ReducersMapObject {
    [key: string]: Reducer<any>;
}

export type ReducersMapObjectWithEnhancer = [ReducersMapObject, ReducerEnhancer];

export interface SubscriptionAPI {
    dispatch: Dispatch<any>;
}
export type Subscription = (api: SubscriptionAPI, done: Function) => void;
export interface SubscriptionsMapObject {
    [key: string]: Subscription;
}

export default interface Model {
    namespace: string;
    state?: any;
    // reducers?: ReducersMapObject | ReducersMapObjectWithEnhancer;
    reducers?: ReduxV3ReducersMapObject | ReducersMapObjectWithEnhancer;
    effects?: EffectsMapObject;
    subscriptions?: SubscriptionsMapObject;
}

@Symous Symous closed this as completed Jul 8, 2019
@Chengma999
Copy link

谢谢老哥,我也是ts初学者,学到不少

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants