[英]How to set the type of property based on the parameter passed in typescript?
我正在创建一个反应应用程序并使用打字稿。 我想要一个具有多个属性的 globalState。 我还需要使用useReducer
。 我为reducer
函数的action
创建了一个接口。 该接口接受一个参数N
,它是动作的name
。 现在我想根据传递的N
参数设置data
类型。
我几乎使用三元运算符创建了它。
export interface IGlobalState {
loading: boolean;
userData: IUserData;
}
interface IUserData {
loggedIn: boolean;
name: string;
}
type GlobalStateActionNames = "setLoading" | "setUserData"
export interface IGlobalStateAction<N extends GlobalStateActionNames = GlobalStateActionNames> {
data: N extends "setLoading"
? boolean
: N extends "setUserData"
? IUserData
: any;
name: N;
}
export const GlobalStateReducer = (
state: IGlobalState,
{name, data}: IGlobalStateAction
): IGlobalState => {
switch(name){
case "setLoading": return {...state, loading: data};
default: return state;
}
};
只有一个问题。 reducer
的data
参数将扩展所有可能是数据值的类型。 因此,当我将loading
设置为data
它会出错。
输入
'boolean | IUserData'
'boolean | IUserData'
不可分配给类型'boolean'
我有两个问题。
注意:我知道我可以通过使用case "setLoading": return {...state, loading: data as boolean};
来解决这个问题case "setLoading": return {...state, loading: data as boolean};
. 但是 globalState 将有许多其他道具。 所以我不想对所有的价值观都这样。
问题是您的IGlobalStateAction
,要根据需要使用它,您需要在内部传递N
泛型,因为这是有条件工作的唯一方法。 由于您无法确定将哪个 action 传递给 reducer,因此无法在此级别传递N
您可以通过保护此类型或将其更改为标准联合来解决该问题,它可能不太通用,但无需任何条件类型即可工作。
// pay attention, type is now simple union
export type IGlobalStateAction =
| {
name: "setLoading",
data: boolean
}
| {
name: 'setUserData',
data: IUserData
}
export const GlobalStateReducer = (
state: IGlobalState,
action: IGlobalStateAction
): IGlobalState => {
switch(action.name){
case "setLoading": return {...state, loading: action.data}; // correctly infers bool
default: return state;
}
};
第二种解决方案是,如果你想离开你的条件类型 - 有类型保护。 考虑:
// here your original type
// type guard narrowing the type
const isActionWithName = <N extends GlobalStateActionNames>
(a: IGlobalStateAction, n: N): a is IGlobalStateAction<N> => a.name === n;
export const GlobalStateReducer = (
state: IGlobalState,
action: IGlobalStateAction
): IGlobalState => {
// using type guard
if (isActionWithName(action, 'setLoading')) {
return {...state, loading: action.data};
}
return state;
};
这里发生了什么 - isActionWithName
函数检查名称并将正确的泛型放入IGlobalStateAction
(这可以在这里发现 - a is IGlobalStateAction<N>
)。 在检查时,我们可以确定它的确切名称,以及它如何影响data
类型。
对不起,我是通过电话做的,但你可以查看我的回购,我有你想要的东西
https://github.com/EnetoJara/-eneto-react-init
export const DO_SOME = ”DO_SOME”;
export type DO_SOME = typeof DO_SOME;
interface AppAction<T,P> {
type: T;
payload?: P;
}
export function actionCreator(someParam; ParamType): AppAction<DO_SOME, ParamType> {
return {
type: DO_SOME,
payload: someParam
}
还记得你可以对他们的功能做这样的事情
function nameOfFunction<T, R> (param: T): Promise<R> {
return httpCal(whatever).then((res: R) => red);
T = 类型 R = 结果遗传学这就是他们的称呼
然后只是为了使用它让我们想象一下
const a = nameOfFunction<UserModel, HttpCode> (user).then((res: HttpCode)=>res);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.