如何将TypeScript类型安全添加到我的redux操作中



我正在用TypeScript编写应用程序,并使用Redux来跟踪我的应用程序状态。我的redux存储状态看起来像这样:

interface AppState {
readonly grid : IGridSettings;
readonly selected : ISelectedSettings;
[key : string] : IGridSettings | ISelectedSettings;
}
interface IGridSettings {
readonly extents : number;
readonly isXY : boolean;
readonly isXZ : boolean;
readonly isYZ : boolean;
readonly spacing : number;
[key : string] : number | boolean;
}
interface ISelectedSettings {
readonly bodyColor : number;
readonly colorGlow : number;
readonly lineColor : number;
readonly selection : number[] | undefined;
[key : string] : number | number[] | undefined;
}

我创建了以下操作来更新存储,但是setPropertyValue函数并不理想,因为它没有类型安全性!

//How to add type safety to this function?
const setPropertyValue = ( property : string[], value : any ) : SetPropertyValueAction => ( {
type: 'SET_PROPERTY_VALUE',
payload: {
property,
value,
}
} );
interface SetPropertyValueAction extends Action {
type : string;
payload : {
property : string[];
value : any;
};
}

我可以在我的代码中这样使用这个操作:

setPropertyValue( ['grid', 'extents'], 100 );

这是可行的,但由于setPropertyValue函数中没有类型安全性,因此没有任何东西限制我向函数中输入无效值,如下所示:

setPropertyValue( ['grid', 'size'], 100 ); //invalid since IGridSettings doesn't have a 'size' property
setPropertyValue( ['grid', 'isXY'], -1 ); //value should be a boolean not a number
setPropertyValue( ['selected', 'bodyColor'], '255' ); //value should be a number not a string

是否有方法重写setPropertyValue函数,使其只接受对AppState中的属性名称有效的参数。此外,传入的值必须与所选属性的正确类型相对应。

也许使用字符串数组来更改属性并不理想,但我不知道有什么更好的方法可以只针对AppState中可用的属性。

如果您需要索引签名,则无法验证该类型的密钥(因为毕竟索引签名意味着该类可以通过任何密钥进行索引,因此任何密钥都是有效的)

为了验证字符串是否是某种类型的密钥,我们可以使用keyof运算符,并结合一些通用类型参数(以捕获传入的实际密钥)

interface AppState {
readonly grid : IGridSettings;
readonly selected: ISelectedSettings;
}
interface IGridSettings {
readonly extents : number;
readonly isXY : boolean;
readonly isXZ : boolean;
readonly isYZ : boolean;
readonly spacing: number;
}
interface ISelectedSettings {
readonly bodyColor : number;
readonly colorGlow : number;
readonly lineColor : number;
readonly selection : number[] | undefined;
}
const setPropertyValue = <KApp extends keyof AppState, KAppProp extends keyof AppState[KApp]>( property : [KApp, KAppProp], value : AppState[KApp][KAppProp] ) : SetPropertyValueAction => ( {
type: 'SET_PROPERTY_VALUE',
payload: {
property,
value,
}
} );
interface SetPropertyValueAction {
type : string;
payload : {
property : PropertyKey[];
value : any;
};
}
setPropertyValue( ['grid', 'extents'], 100 );
setPropertyValue( ['grid', 'size'], 100 ); //err
setPropertyValue( ['grid', 'isXY'], -1 ); //err
setPropertyValue( ['selected', 'bodyColor'], '255' );// err 

最新更新