ポストjQueryの要件

jQueryからの脱却が叫ばれる所以はクエリによりカプセル化の境界を簡単に逸脱する局所性のなさ、また要素やコンポーネント間の連携を求めるにはクエリでは対象の存在も同一性も不確実すぎるなどの理由から大規模なコードベースを構築できないためです。これを克服しようとするとクエリを取り除かなければなりませんが取り除いただけでは要素へのアクセス手段がなくなり使い物にならないのでクエリの代わりになるDOM制御方法を用意しなければなりません。加えてjQueryはDOMの構築も苦手なのでこれも補ってやらねばなりません。

これを解決するには静的型付き言語でのみ利用できるアプローチですがDOM構造を静的に型付けし型をたどることで目的とする要素を操作できるようにする方法が考えられます。正しいパスは型によって示され、間違ったパスは型によってエラーとなり、対象の存在と構造的同一性が保証されます。TypeScriptでは以下のような定義と操作が可能です。構造には文字列、配列、任意のフィールドを持つ構造体のいずれかを選択できます。

import TypedHTML from 'typed-dom';

const component = TypedHTML.article({ id: 'id' }, {
  style: TypedHTML.style(`$scope ul { width: 100px; }`),
  title: TypedHTML.h1(`title` as string),
  content: TypedHTML.ul([
    TypedHTML.li(`item` as string),
    TypedHTML.li(`item`),
  ])
});
// inspect
component.element.outerHTML; // '<article id="id"><style>#id ul { width: 100px; }</style><h1>title</h1><ul><li>item</li><li>item</li></ul></article>'
component.children.title.element.outerHTML; // '<h1>title</h1>'
component.children.title.children; // 'title'
component.children.content.element.outerHTML; // '<ul><li>item</li><li>item</li></ul>'
component.children.content.children[0].children; // 'item'

// update
// - text
component.children.title.children = 'Title';
component.children.title.element.outerHTML; // '<h1>Title</h1>'

// - struct
component.children.content.children = [
  TypedHTML.li('Item')
];
component.children.content.element.outerHTML; // '<ul><li>Item</li></ul>'

// - TypedHTML
component.children.title = TypedHTML.h1('Title!');
component.children.content = TypedHTML.ul([
  TypedHTML.li('Item!')
]);
component.element.outerHTML; // '<article id="id"><style>#id ul { width: 100px; }</style><h1>Title!</h1><ul><li>Item!</li></ul></article>'

HTML以下のDOMを完全に静的型付けすることも可能です。ただしそのままでは末端の要素へのパスが長くなりすぎるため適切な単位で抽象化が必要になります。

ポストjQueryにはこのようにクエリを除去しカプセル化を守るライブラリが求められます。なお仮想DOMについてはDOMをコンポーネントなど大きな単位で更新するコストを下げるための技術なので最小コストで更新できるのであれば不要です。

github.com