I have this object:
const task = ref<Task>({
name: '',
description: '',
type: undefined,
level: 'tactic',
participants: undefined,
stages: undefined,
});
export interface Task extends CommonEntity {
description?: string;
type?: TaskType;
level?: EntityLevel;
participants?: number;
stages?: TaskTypeStage[];
questions?: TaskQuestion[];
materials?: TaskMaterial[];
indicators?: TaskIndicator[];
duration?: number;
images?: [];
program_id?: number;
roles?: TaskRole[];
tables?: TaskTable[];
competences?: TaskCompetence[];
task_type_id?: number;
}
export interface CommonEntity {
id?: number;
name?: string;
created_at?: string;
updated_at?: string;
errors?: ApiErrors;
delete?: boolean;
isTemporaryIdAdded?: boolean;
}
in some method I want to change task objects.
function handleSubmit() {
task.value.materials = removeTemporaryIdFromArray<TaskMaterial>(task.value.materials);
task.value.questions = removeTemporaryIdFromArray<TaskQuestion>(task.value.questions);
task.value.roles = removeTemporaryIdFromArray<TaskRole>(task.value.roles);
task.value.tables = removeTemporaryIdFromArray<TaskTable>(task.value.tables);
}
export function removeTemporaryIdFromArray<T>(
entity: TaskMaterial[] | TaskQuestion[] | TaskRole[] | TaskTable[] | undefined
) {
if (entity) {
return entity
.filter((item) => !item.delete || !item.isTemporaryIdAdded)
.map((item) => Object.assign({}, removeTemporaryId<T>(item)));
}
}
export function removeTemporaryId<T>(item: CommonEntity): T {
const { id, isTemporaryIdAdded, ...rest } = item;
return isTemporaryIdAdded ? (rest as T) : { id, ...(rest as T) };
}
I'm watching a way to change function handleSubmit without write four times task.value[key] = removeTemporaryIdFromArray
. To something with ['objectKey1', 'objectKey2'].forEach(key => object[key] = changeFunction(object[key]) )
I'm cheating and write function below. And ts don't see mistakes
(['materials', 'questions', 'roles', 'tables'] as (keyof typeof task.value)[]).forEach((key) => {
task.value[key] = removeTemporaryIdFromArray<typeof key>(task.value[key] as TaskMaterial[]) as undefined;
});
What I don't understand is why task.value[key]
is waiting undefined
as value. I understand, that solution it is not quite right. Can you suggest a better solution?
I think the affectation is not ok
task.value[key] = removeTemporaryIdFromArray<typeof key>(task.value[key] as TaskMaterial[]) as undefined;
because removeTemporaryIdFromArray can not choose between various types (TaskMaterial[] | TaskQuestion[] | TaskRole[] | TaskTable[] | undefined) when set task.value[key].
I think you can work around with removeTemporaryIdFromArray_InPlace.
Here is my proposal (little verbose may be), and it is difficult to test without context. But typescript say ok.
// helper type
type Writable<T> = { -readonly [K in keyof T]: T[K] };
// your properties to loop on
const KeyNames = ["materials", "questions", "roles", "tables"] as const;
// type helper with only the 'good' keys, never undefined (but we do not care.)
type SubPropertyTask = Required<Pick<Task, typeof KeyNames[number]>>;
// your properties to loop on transformed in an array of keys, that you can loop on really.
const WriteableKeyNames = KeyNames as Writable<typeof KeyNames> as Array<keyof SubPropertyTask>;
// your new submit
function handleSubmitV3() {
// loop on key
WriteableKeyNames.forEach((key: keyof SubPropertyTask) => {
// the call wich is not so trivial
// < type of first element of the array (because we know its array)
// need also type of the key, taht can not be infered.
removeTemporaryIdFromArrayInplace<SubPropertyTask[typeof key][0], typeof key>(task[key], key);
});
}
// T might be written like this : T extends TaskQuestion | TaskMaterial | TaskRole | TaskTable
// but if you need to add other property, name should be enougth
export const removeTemporaryIdFromArrayInplace = <T, E extends keyof SubPropertyTask>(entity: Array<T> | undefined, e: E): void => {
// do your own filter/
const filteredEntity = entity?.filter((taskObject: T) => taskObject);
// set up the new value, which would work, with this particlar cast.
// Because at this time typeof task[e] is same as T and as SubPropertyTask[E] | undefined
// ... I think.
task[e] = filteredEntity as SubPropertyTask[E] | undefined;
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.