首先,FormData 是一个内置类型,如下所示:
interface FormData {
append(name: string, value: string | Blob, fileName?: string): void;
delete(name: string): void;
get(name: string): FormDataEntryValue | null;
getAll(name: string): FormDataEntryValue[];
has(name: string): boolean;
set(name: string, value: string | Blob, fileName?: string): void;
forEach(callbackfn: (value: FormDataEntryValue, key: string, parent: FormData) => void, thisArg?: any): void;
}
interface FormData {
[Symbol.iterator](): IterableIterator<[string, FormDataEntryValue]>;
/** Returns an array of key, value pairs for every entry in the list. */
entries(): IterableIterator<[string, FormDataEntryValue]>;
/** Returns a list of keys in the list. */
keys(): IterableIterator<string>;
/** Returns a list of values in the list. */
values(): IterableIterator<FormDataEntryValue>;
}
因此,我认为重命名您的自定义界面是个好主意。
错误:
Type 'string | number' is not assignable to type 'never'.
Type 'string' is not assignable to type 'never'.(2322)
在
nextState[action.field] = action.payload!;
从类型的角度来看,action.payload 可能是 string | number | undefined,而action.field 可能是来自 CustomFormData 的任何键。这意味着action.field 和action.payload 之间没有直接关联。
更多,
interface FieldAction {
type: FieldChangeType;
field: keyof CustomFormData;
payload?: CustomFormData[keyof CustomFormData];
}
非常不安全。
考虑一下:
const unsafeAction: FieldAction = {
type: FieldChangeType.TextInput,
field: 'cluster',
payload: 42
}
这个对象的表示无效,因为payload 应该是字符串。
为了修复它,您应该使无效状态无法表示。考虑这个例子:
type FieldAction = {
[Field in keyof CustomFormData]: {
type: FieldChangeType,
field: Field,
payload?: CustomFormData[Field]
}
}[keyof CustomFormData]
const ok: FieldAction = {
type: FieldChangeType.TextInput,
field: 'cluster',
payload: 'str'
} // ok
const expected_error: FieldAction = {
type: FieldChangeType.TextInput,
field: 'cluster',
payload: 42
} // error
我们创建了所有允许状态的联合。顺便说一句,TypeScript 不喜欢突变,您应该始终考虑到这一点。
这是我的建议:
interface CustomFormData {
applicationName: string;
cluster: string;
stackCode: number;
GitHubToken: string;
}
enum FieldChangeType {
TextInput,
Toggle,
}
type FieldAction = {
[Field in keyof CustomFormData]: {
type: FieldChangeType,
field: Field,
payload?: CustomFormData[Field]
}
}[keyof CustomFormData]
const makePayload = (state: CustomFormData, action: FieldAction)
: CustomFormData => ({
...state,
[action.field]: action.payload
})
function useFormRedux() {
function reducer(preState: CustomFormData, action: FieldAction) {
const nextState: CustomFormData = null as any;
switch (action.type) {
case FieldChangeType.TextInput:
return makePayload(preState, action)
}
return nextState;
}
}
Playground
Here你可以找到官方解释
您可以在此处找到有关 htis 主题的更多问题/答案:
first、second、almost a duplicate
Here你可以找到我的文章,里面有一些例子和链接
主要用途说明
type FieldAction = {
/**
* This syntax mean iteration
* See docs https://www.typescriptlang.org/docs/handbook/2/mapped-types.html
*/
[Field in keyof CustomFormData]: {
type: FieldChangeType,
field: Field,
payload?: CustomFormData[Field]
}
}
/**
* I have removed [keyof CustomFormData] from the end for the sake of readability
* You can instead wrap FieldAction into Values utility type
*/
type Values<T> = T[keyof T]
{
type Test1 = Values<{ a: 1, b: 2 }> // 1 | 2
}
type Result = Values<FieldAction>
Playground