@wordpress/scripts (the official Webpack/Babel build tool for WordPress blocks) supports TypeScript out of the box — adding a tsconfig.json is all that is needed to enable type checking for block attributes, store selectors, and editor component props. TypeScript in block development catches attribute shape mismatches, incorrect useSelect return types, and missing block API fields before the code runs in the editor.
Problem: WordPress block development uses JSX and modern JavaScript, but the lack of TypeScript in the project means type errors in block attributes, editor component props, and REST API response shapes are caught only at runtime.
Solution: Add TypeScript to an existing block by installing @wordpress/scripts (which includes TypeScript support) and renaming entry files from .js to .ts/.tsx. Use the @wordpress/types package for WordPress-specific type definitions. Type block attributes with an interface that matches block.json attributes, and use BlockEditProps<Attributes> from @wordpress/blocks for the edit component's props.
The setup below adds TypeScript to an existing @wordpress/scripts block plugin, types block attributes with an interface, types useSelect and useDispatch calls, and shows the correct types for registerBlockType and BlockEditProps.
# 1. Add TypeScript and WordPress type packages
npm install --save-dev typescript \
@types/wordpress__blocks \
@types/wordpress__block-editor \
@types/wordpress__components \
@types/wordpress__data \
@types/wordpress__element
# 2. @wordpress/scripts already handles .ts/.tsx files via its Webpack config
# Just rename edit.js → edit.tsx, index.js → index.ts and add tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution":"bundler",
"jsx": "react",
"jsxFactory": "window.wp.element.createElement",
"strict": true,
"noEmit": true,
"baseUrl": ".",
"paths": {
"@wordpress/*": ["node_modules/@wordpress/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "build"]
}
// src/edit.tsx — fully typed block edit component
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, RangeControl, ToggleControl } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import type { BlockEditProps } from '@wordpress/blocks';
// 1. Type the block attributes interface
interface MyBlockAttributes {
columns: number;
showDate: boolean;
categoryId: number | undefined;
}
// 2. Typed edit component — BlockEditProps provides typed setAttributes
export function Edit( { attributes, setAttributes }: BlockEditProps ) {
const { columns, showDate, categoryId } = attributes;
// 3. Typed useSelect — TypeScript knows the return type of getCategories
const categories = useSelect( ( select ) => {
return select( coreStore ).getEntityRecords( 'taxonomy', 'category', {
per_page: 20,
} );
}, [] );
const blockProps = useBlockProps();
return (
<>
setAttributes( { columns: val } ) }
min={ 1 }
max={ 6 }
/>
setAttributes( { showDate: val } ) }
/>
{ columns } columns — { showDate ? 'with' : 'without' } date
{ categories && (
{ categories.map( cat => (
- { cat.name }
) ) }
) }
>
);
}
// 4. Type-check your block.json attributes at compile time
import metadata from './block.json';
import { registerBlockType } from '@wordpress/blocks';
registerBlockType( metadata, {
edit: Edit,
save: () => null, // dynamic block
} );
NOTE: @wordpress/scripts transpiles TypeScript with Babel (not tsc), meaning it strips types without type-checking at build time — you get fast builds but no compile-time type errors; add "typecheck": "tsc --noEmit" to your package.json scripts and run it in CI to get actual type safety, since the build will succeed even with type errors otherwise.