#javascript #typescript #typescript-generics
#javascript #typescript #typescript-generics
Вопрос:
Я пишу функцию, которая будет перебирать ряд объектов, каждый из которых содержит массив. Каждый элемент в массиве может иметь condition
функцию, которая проверяет, следует ли его добавлять.
После некоторых попыток и чтения общих терминов я все еще застрял!
Ошибки, которые я вижу: 'Property 'condition' / 'items' / 'sections' does not exist on type 'T'
Кто-нибудь может помочь мне сделать эту работу? Спасибо!
Типы
export interface ContractDetailBO {
sections: ContractSectionBO[];
condition?: Function;
}
export interface ContractSectionBO {
items: ContractSectionItemBO[];
condition?: Function;
}
export interface ContractSectionItemBO {
label: string;
condition?: Function;
}
export interface ContractBO {
encryptedContractId: string;
}
export type AnyBO = ContractDetailBO | ContractSectionBO | ContractSectionItemBO;
Рекурсивная функция
export const isOfType = <T>(
varToBeChecked: any,
propertyToCheckFor: keyof T
): varToBeChecked is T =>
(varToBeChecked as T)[propertyToCheckFor] !== undefined;
export function populate<T extends AnyBO>(inputArray: T[], config: Config): T[] {
const returnItems: T[] = [];
inputArray.map((item: T) => {
// include this item if the condition passes or is not defined
if (item.condition === undefined || item.condition(config)) {
const itemToPopulate = { ...item };
// check type of item so we know the next array to iterate
if (isOfType<ContractDetailBO>(item, 'sections')) {
const nextArray: ContractSectionBO[] = populate(item.sections, config);
itemToPopulate.sections = nextArray;
}
if (isOfType<ContractSectionBO>(item, 'items')) {
const leaves: ContractSectionItemBO[] = populate(item.items, config);
itemToPopulate.items = leaves;
}
returnItems.push(itemToPopulate);
}
});
return returnItems;
}
const populatedBOs:ContractDetailBO = populate(myContractDetailBO, myContractBO)
Ответ №1:
Вы можете попробовать это.
export type Config = {};
export interface BaseBO {
condition?: (config: Config) => boolean;
}
export interface ContractDetailBO extends BaseBO {
sections: ContractSectionBO[];
}
export interface ContractSectionBO extends BaseBO {
items: ContractSectionItemBO[];
}
export interface ContractSectionItemBO extends BaseBO {
label: string;
}
export type AnyBO = ContractDetailBO | ContractSectionBO | ContractSectionItemBO;
function isContractDetailBO(target: AnyBO): target is ContractDetailBO {
return (target as ContractDetailBO).sections != null;
}
function isContractSectionBO(target: AnyBO): target is ContractSectionBO {
return (target as ContractSectionBO).items != null;
}
export function populate<T extends AnyBO>(inputArray: T[], config: Config): T[] {
const returnItems: T[] = [];
for (const item of inputArray) {
// include this item if the condition passes or is not defined
if (!item.condition || item.condition(config)) {
const itemToPopulate = { ...item };
// check type of item so we know the next array to iterate
if (isContractDetailBO(itemToPopulate)) {
const nextArray: ContractSectionBO[] = populate(itemToPopulate.sections, config);
itemToPopulate.sections = nextArray;
}
if (isContractSectionBO(itemToPopulate)) {
const leaves: ContractSectionItemBO[] = populate(itemToPopulate.items, config);
itemToPopulate.items = leaves;
}
returnItems.push(itemToPopulate);
}
}
return returnItems;
}
Комментарии:
1. Большое спасибо @givi, это отлично работает 🙂 Я все еще чувствую, что слишком сложно подхожу к своей проблеме, но это отличное решение. Спасибо!