Dva: 关于集成typescript后,models写法的疑惑

Created on 6 Jun 2019  ·  10Comments  ·  Source: dvajs/dva

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

Most helpful comment

感谢楼上各位老哥的推荐,但是作为一个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;
}

All 10 comments

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

import { Model } from 'dva';

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

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

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

import { Model } from 'dva';

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

as是类型断言

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

@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;

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

用这个吧 dva-model-creator

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

感谢楼上各位老哥的推荐,但是作为一个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;
}

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

Was this page helpful?
0 / 5 - 0 ratings