Gutenberg のカスタムブロックを TypeScript で書く

note

TypeScript初心者。
静的型付けの経験はほぼ皆無。
さすがに基本的な型は分かる。
Gutenberg は良く分かってない。
画像設定させたりテキスト入力させたりが限度。

ts のトランスパイラやカスタムブロックを WordPress へ組み込む方法については省略。

以上、ご留意。

ブロックエディタの定義ファイルは @types/wordpress__block-editor

edit, save に返すクラスコンポーネントは @wordpress/elementComponent を継承すると楽。
React から引っ張ってきても良いけど型の設定が面倒臭い。

edit は BlockEditProps, save は BlockSavePorps をジェネリクスとして設定する。
BlockEditProps と BlockSaveProps は @wordpress/blocks に定義されている。

BlockEditProps と BlockSaveProps には attributes の interface をジェネリクスとして設定する。

設定は @wordpress/blocks の BlockConfiguration を設定する。
ジェネリクスは上記で設定した attributes の interface。

attribues の各プロパティには @wordpress/blocks の BlockAttribute<型> を設定する。(この辺なんか違う気がしてる)

icon は @wordpress/blocks の BlockIcon を設定する。

最悪 @types/wordpress__block-editor を頑張って読めばどうにかなる。
JSX のコンポーネントなのでなんとなくで割と書ける。
分かり辛いのは動的な部分、 attributes の扱い。

以下のサンプルは動作未確認。

import { Component } from '@wordpress/element';
import {
    BlockEditProps,
    BlockSaveProps,
    BlockAttribute,
    BlockIcon,
    BlockConfiguration,
    registerBlockType
} from '@wordpress/blocks';
import { PlainText } from '@wordpress/block-editor';

interface Attribute {
    text: string;
}

interface AttributeEntity {
    text: BlockAttribute<string>
}

const icon: BlockIcon = 'layout';

const attributes: AttributeEntity = {
    text: {
        type: 'string',
        source: 'html',
        selector: '.text',
    },
}

const edit = class extends Component<BlockEditProps<Attributes>> {
    render () {
        const { className, attributes, setAttributes } = this.props;

        return (
            <div className="text">
                <PlainText
                    onChange={(text) => setAttributes({text})}
                    value={attributes.text}
                />
            </div>
        );
    }
};

const save = class extends Component<BlockSaveProps<Attributes>> {
    render () {
        const { attributes } = this.props;

        return (
            <div className="text">
                { attributes.text }
            </div>
        )
    }
};

const config: BlockConfiguration<Attributes> = {
    title: 'テキスト',
    category: 'layout',
    icon,
    attributes,
    edit,
    save,
};

registerBlockType('gcb/text', config);