打字稿 |通用可索引类型中缺少 属性
Typescript | missing property in generic indexable type
我很好奇 Redux Toolkit 是如何工作的,并试图复制一个基本的实现。但是我 运行 遇到了一个关于可索引类型 AnyAction
和具有定义的 属性 类型 PayloadAction
的问题 payload
.
builder.addCase
函数需要一个 reducer 函数作为第二个参数。该减速器又具有 2 个参数 state
和 action
。 action
参数默认为 AnyAction
。当我手动将 action
的类型设置为 PayloadAction<P>
时,会弹出一个关于 Action<string>
.
类型中缺少 属性 payload
的错误
我似乎无法理解它,希望有人能帮助我并向我解释为什么这不起作用。
export interface Action<T extends any = string> {
type: T
}
export interface AnyAction extends Action {
[extraProps: string]: any
}
export interface PayloadAction<P = any> extends Action {
payload: P
}
const builder = {
addCase(
typeOrActionCreator: string, reducer: <A extends Action = AnyAction>(state: any, action: A) => void
) {
return builder
}
}
builder.addCase('test', (state, action: PayloadAction<number>) => {
action.payload
}).addCase('tester', (state, action) => {
action
})
您的使用方式,addCase()
应该是通用的,而 reducer
参数不是通用的,它只是使用 addCase()
.
中的类型参数
试试这个:
const builder = {
addCase<A extends Action = AnyAction>(
typeOrActionCreator: string,
reducer: (state: any, action: A) => void
) {
return builder
}
}
您应该将泛型放在要推断类型的位置。在您调用 addCase()
的情况下,您会推断出有效载荷类型,然后 reducer
函数将始终使用该有效载荷类型。它已被锁定,您不能传递其他类型作为有效负载。这就是为什么 reducer
不是 通用函数。
您可以像这样使用 createAction 并传递有效载荷的类型:
const incrementByAmount = createAction<number, 'increment'>('increment')
现在,如果将鼠标悬停在 action
上,您将看到类型为 increment
,有效负载为数字。
在 redux 工具包中,他们已经有一个如何设置有效负载类型的示例。
https://redux-toolkit.js.org/api/createreducer
来自 Redux 工具包文档的完整示例。
import { createAction, createReducer } from '@reduxjs/toolkit'
interface CounterState {
value: number
}
const increment = createAction('counter/increment')
const decrement = createAction('counter/decrement')
const incrementByAmount = createAction<number>('counter/incrementByAmount')
const initialState = { value: 0 } as CounterState
const counterReducer = createReducer(initialState, (builder) => {
builder
.addCase(increment, (state, action) => {
state.value++
})
.addCase(decrement, (state, action) => {
state.value--
})
.addCase(incrementByAmount, (state, action) => {
state.value += action.payload
})
})
我很好奇 Redux Toolkit 是如何工作的,并试图复制一个基本的实现。但是我 运行 遇到了一个关于可索引类型 AnyAction
和具有定义的 属性 类型 PayloadAction
的问题 payload
.
builder.addCase
函数需要一个 reducer 函数作为第二个参数。该减速器又具有 2 个参数 state
和 action
。 action
参数默认为 AnyAction
。当我手动将 action
的类型设置为 PayloadAction<P>
时,会弹出一个关于 Action<string>
.
payload
的错误
我似乎无法理解它,希望有人能帮助我并向我解释为什么这不起作用。
export interface Action<T extends any = string> {
type: T
}
export interface AnyAction extends Action {
[extraProps: string]: any
}
export interface PayloadAction<P = any> extends Action {
payload: P
}
const builder = {
addCase(
typeOrActionCreator: string, reducer: <A extends Action = AnyAction>(state: any, action: A) => void
) {
return builder
}
}
builder.addCase('test', (state, action: PayloadAction<number>) => {
action.payload
}).addCase('tester', (state, action) => {
action
})
您的使用方式,addCase()
应该是通用的,而 reducer
参数不是通用的,它只是使用 addCase()
.
试试这个:
const builder = {
addCase<A extends Action = AnyAction>(
typeOrActionCreator: string,
reducer: (state: any, action: A) => void
) {
return builder
}
}
您应该将泛型放在要推断类型的位置。在您调用 addCase()
的情况下,您会推断出有效载荷类型,然后 reducer
函数将始终使用该有效载荷类型。它已被锁定,您不能传递其他类型作为有效负载。这就是为什么 reducer
不是 通用函数。
您可以像这样使用 createAction 并传递有效载荷的类型:
const incrementByAmount = createAction<number, 'increment'>('increment')
现在,如果将鼠标悬停在 action
上,您将看到类型为 increment
,有效负载为数字。
在 redux 工具包中,他们已经有一个如何设置有效负载类型的示例。 https://redux-toolkit.js.org/api/createreducer
来自 Redux 工具包文档的完整示例。
import { createAction, createReducer } from '@reduxjs/toolkit'
interface CounterState {
value: number
}
const increment = createAction('counter/increment')
const decrement = createAction('counter/decrement')
const incrementByAmount = createAction<number>('counter/incrementByAmount')
const initialState = { value: 0 } as CounterState
const counterReducer = createReducer(initialState, (builder) => {
builder
.addCase(increment, (state, action) => {
state.value++
})
.addCase(decrement, (state, action) => {
state.value--
})
.addCase(incrementByAmount, (state, action) => {
state.value += action.payload
})
})