#typescript
Вопрос:
Мой вопрос связан с тем, что я не знаю полностью машинописный текст (унаследованный проект), поэтому, пожалуйста, поделитесь со мной:
У меня есть очень повторяющийся код, который выглядит примерно так:
import {EventA, EventB, .... EventG} from './events'
import {EntityA, EntityB, ....EntityG} from './entities'
//all the event objects are defined: EventA extends Event
//all the entity objects are defined: EntityA extends Entity
export function handleEventA(event: eventA): void {
let entity = new EntityA(event.id)
entity.date = event.date
entity.address = event.address
...
entity.SomethingUniqueToEntityA = event.SomethingUniqueToEntityA
entity.save()
}
...
export function handleEventG(event: eventG): void {
let entity = new EntityG(event.id)
entity.date = event.date
entity.address = event.address
...
entity.SomethingUniqueToEntityG = event.SomethingUniqueToEntityG
entity.save()
}
Как вы можете видеть, это очень повторяющееся действие: я всегда создаю экземпляр сущности, соответствующей событию, и всегда копирую одни и те же 2-3 поля из события в сущность, прежде чем приступить к обработке уникальных полей сущности.
Я думал, что у меня будет какой-нибудь декоратор (или, может быть, фабрика??) функция, которая позволит мне сделать что-то вроде:
function decorate(entity: Entity, event: Event): Entity {
entity.date = event.date
entity.address = event.address
return entity
}
export function handleEventA(event: eventA): void {
let entity = new EntityA(event.id)
entity = decorate(entity, event)
...
entity.SomethingUniqueToEntityA = event.SomethingUniqueToEntityA
entity.save()
}
Или, может быть, даже какая-то заводская функция, которая создаст экземпляры сущностей.
Я попытался определить что-то вроде decorate(entity: EntityA | EntityB |... EntityG, event: EventA | EventB |... EventG)
, но это также становится громоздким и повторяющимся.
Моя проблема в следующем: как мне определить decorate
функцию, позволяющую использовать все сущности и события в качестве параметров? Нужно ли мне вообще возвращаться entity
или это вызывается по ссылке?
Ответ №1:
Самым простым способом должно быть определение только подписи, необходимой для вашей decorate
функции. Это возможно благодаря структурной типизации TypeScript. Достаточно, чтобы «форма» типа совпадала — поэтому любое Event
( EventA
, EventB
) или Entity
имеющее эти 2 свойства может быть передано в качестве входного параметра.
interface IDateAndAddress {
date: Date,
address: string
}
function decorate(entity: IDateAndAddress, event: IDateAndAddress): void {
entity.date = event.date;
entity.address = event.address;
}
Вы можете быть немного более конкретным, чтобы убедиться, что вы не можете поменять entity
местами и event
по ошибке, при вызове decorate
функции, но это суть решения.
Комментарии:
1. Я не контролирую ни коды сущностей, ни коды событий — они генерируются. Кроме того, свойства не являются свойствами верхнего уровня, например, чтобы получить адрес, мне нужно сделать что-то вроде
entity.address = event.block.address
.2. Затем просто сформируйте
IDataAndAdress
так, как вам нужно, включая вложенные объекты. Форма должна соответствовать свойствам, которыми вы хотите управлять в функции, не более того. Это сработает.3. Я попробовал ваше решение: определил интерфейс и добавил
export function decorate(a: IEntityFields, b: Event) : void {}
, что я получаюTS2304: Cannot find name 'IEntityFields'
, со строкой, выделяющейIEntityFields
— даже если она определена прямо над функцией. Является ли это результатомexport
?4. Это не должно быть результатом экспорта. Трудно сказать, что ты делаешь не так. Может быть, опечатка? Здесь есть рабочий образец, если это поможет.
5. Я ценю демонстрационный код. Я не контролирую компилятор TS здесь (код генерируется библиотекой), но если я использую запятые
interface
вместо точки с запятой или оставляю его пустым, он жалуется на типы (TS003). Значит, что-то не так.