추상 private 는 ts가 지원하지 않는다.
public 메서드는 private 메서드 위에 작성하는 것이 좋다.
제네릭과 상속으로 코드 리팩토링을 해보자.
type Listener<T> = (items: T[]) => void;
class State<T> {
protected listeners: Listener<T>[] = [];
addListener(listenerFn: Listener<T>) {
this.listeners.push(listenerFn);
}
}
class ProjectState extends State<Project> {
// ...
private constructor() {
super();
}
}
abstract class Component<T extends HTMLElement, U extends HTMLElement> {
templateElement: HTMLTemplateElement;
hostElement: T;
element: U;
constructor(
templateId: string,
hostElementId: string,
insertAtStart: boolean,
newElementId?: string
) {
this.templateElement = document.getElementById(templateId)! as HTMLTemplateElement;
this.hostElement = document.getElementById(hostElementId)! as T;
const importedNode = document.importNode(this.templateElement.content, true);
this.element = importedNode.firstElementChild as U;
if (newElementId) {
this.element.id = newElementId;
}
this.attach(insertAtStart);
}
private attach(insertAtBeginning: boolean) {
this.hostElement.insertAdjacentElement(insertAtBeginning ? 'afterbegin' : 'beforeend', this.element);
}
abstract configure(): void;
abstract renderContent(): void;
}
class ProjectList extends Component<HTMLDivElement, HTMLElement> {
assignedProjects: Project[];
constructor(private type: 'active' | 'finished') {
super('project-list', 'app', false, `${type}-projects`);
this.assignedProjects = [];
this.configure();
this.renderContent();
}
configure() {...}
renderContent() {...}
private renderProjects() {...}
}
class ProjectInput extends Component<HTMLDivElement, HTMLFormElement>{
titleInputElement: HTMLInputElement;
descriptionInputElement: HTMLInputElement;
peopleInputElement: HTMLInputElement;
constructor() {
super('project-input', 'app', true, 'user-input');
this.titleInputElement = this.element.querySelector('#title') as HTMLInputElement;
this.descriptionInputElement = this.element.querySelector('#description') as HTMLInputElement;
this.peopleInputElement = this.element.querySelector('#people') as HTMLInputElement;
this.configure();
}
configure() {...}
renderContent() {}
private gatherUserInput(): [string, string, number] | void {...}
private clearInputs() {...}
@autobind
private submitHandler(event: Event) {...}
}