Skip to content

Commit

Permalink
Core Data: Fixes necessary for converting to TypeScript
Browse files Browse the repository at this point in the history
In this commit we're cleaning up type issues in the core-data package
that prevent us from telling TypeScript to run on the package and all
of its existing code, even the JS files.

After these changes we should be able to do so and start converting
more modules to TypeScript with less friction.

This patch follows a series of other smaller updates:
 - #39212
 - #39214
 - #39225
 - #39476
 - #39477
 - #39479
 - #39480
 - #39525
 - #39526
 - #39655
 - #39656
 - #39659

It was built in order to support ongoing work to add types to the
`getEntityRecord` family of functions in #39025.
  • Loading branch information
dmsnell committed Mar 31, 2022
1 parent aa3193a commit 68306ab
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 36 deletions.
2 changes: 1 addition & 1 deletion docs/reference-guides/data/data-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ _Parameters_
- _state_ `Object`: State tree.
- _kind_ `string`: Entity kind.
- _name_ `string`: Entity name.
- _recordId_ `number`: Record ID.
- _recordId_ `number|string`: Record ID.

_Returns_

Expand Down
2 changes: 1 addition & 1 deletion packages/core-data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,7 @@ _Parameters_
- _state_ `Object`: State tree.
- _kind_ `string`: Entity kind.
- _name_ `string`: Entity name.
- _recordId_ `number`: Record ID.
- _recordId_ `number|string`: Record ID.

_Returns_

Expand Down
1 change: 1 addition & 0 deletions packages/core-data/src/batch/default-processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default async function defaultProcessor( requests ) {

const results = [];

// @ts-ignore We would have crashed or never gotten to this point if we hadn't received the maxItems count.
for ( const batchRequests of chunk( requests, maxItems ) ) {
const batchResponse = await apiFetch( {
path: '/batch/v1',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { __ } from '@wordpress/i18n';
/**
* Filters the search by type
*
* @typedef { 'post' | 'term' | 'post-format' } WPLinkSearchType
* @typedef { 'attachment' | 'post' | 'term' | 'post-format' } WPLinkSearchType
*/

/**
Expand Down Expand Up @@ -38,6 +38,17 @@ import { __ } from '@wordpress/i18n';
* @property {WPKind} [kind] Link kind of post-type or taxonomy
*/

/**
* @typedef WPLinkSearchResultAugments
*
* @property {{kind: WPKind}} [meta] Contains kind information.
* @property {WPKind} [subtype] Optional subtype if it exists.
*/

/**
* @typedef {WPLinkSearchResult & WPLinkSearchResultAugments} WPLinkSearchResultAugmented
*/

/**
* @typedef WPEditorSettings
*
Expand Down Expand Up @@ -82,6 +93,7 @@ const fetchLinkSuggestions = async (

const { disablePostFormats = false } = settings;

/** @type {Promise<WPLinkSearchResult>[]} */
const queries = [];

if ( ! type || type === 'post' ) {
Expand Down Expand Up @@ -177,7 +189,8 @@ const fetchLinkSuggestions = async (
return Promise.all( queries ).then( ( results ) => {
return results
.reduce(
( accumulator, current ) => accumulator.concat( current ), // Flatten list.
( /** @type {WPLinkSearchResult[]} */ accumulator, current ) =>
accumulator.concat( current ), // Flatten list.
[]
)
.filter(
Expand All @@ -189,27 +202,24 @@ const fetchLinkSuggestions = async (
}
)
.slice( 0, perPage )
.map(
/**
* @param {{ id: number, meta?: object, url:string, title?:string, subtype?: string, type?: string }} result
*/
( result ) => {
const isMedia = result.type === 'attachment';

return {
id: result.id,
url: isMedia ? result.source_url : result.url,
title:
decodeEntities(
isMedia
? result.title.rendered
: result.title || ''
) || __( '(no title)' ),
type: result.subtype || result.type,
kind: result?.meta?.kind,
};
}
);
.map( ( /** @type {WPLinkSearchResultAugmented} */ result ) => {
const isMedia = result.type === 'attachment';

return {
id: result.id,
// @ts-ignore fix when we make this a TS file
url: isMedia ? result.source_url : result.url,
title:
decodeEntities(
isMedia
? // @ts-ignore fix when we make this a TS file
result.title.rendered
: result.title || ''
) || __( '(no title)' ),
type: result.subtype || result.type,
kind: result?.meta?.kind,
};
} );
} );
};

Expand Down
15 changes: 12 additions & 3 deletions packages/core-data/src/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { ifMatchingAction, replaceAction } from './utils';
import { reducer as queriedDataReducer } from './queried-data';
import { rootEntitiesConfig, DEFAULT_ENTITY_KEY } from './entities';

/** @typedef {import('./types').AnyFunction} AnyFunction */

/**
* Reducer managing terms state. Keyed by taxonomy slug, the value is either
* undefined (if no request has been made for given taxonomy), null (if a
Expand Down Expand Up @@ -185,7 +187,7 @@ export function themeGlobalStyleVariations( state = {}, action ) {
*
* @param {Object} entityConfig Entity config.
*
* @return {Function} Reducer.
* @return {AnyFunction} Reducer.
*/
function entity( entityConfig ) {
return flowRight( [
Expand Down Expand Up @@ -406,7 +408,11 @@ export const entities = ( state = {}, action ) => {

/** @typedef {Array<Object> & UndoStateMeta} UndoState */

/** @type {UndoState} */
/**
* @type {UndoState}
*
* @todo Given how we use this we might want to make a custom class for it.
*/
const UNDO_INITIAL_STATE = Object.assign( [], { offset: 0 } );

/** @type {Object} */
Expand All @@ -416,7 +422,7 @@ let lastEditAction;
* Reducer keeping track of entity edit undo history.
*
* @param {UndoState} state Current state.
* @param {Object} action Dispatched action.
* @param {Object} action Dispatched action.
*
* @return {UndoState} Updated state.
*/
Expand Down Expand Up @@ -455,6 +461,7 @@ export function undo( state = UNDO_INITIAL_STATE, action ) {
let nextState;

if ( isUndoOrRedo ) {
// @ts-ignore we might consider using Object.assign({}, state)
nextState = [ ...state ];
nextState.offset =
state.offset + ( action.meta.isUndo ? -1 : 1 );
Expand Down Expand Up @@ -494,6 +501,7 @@ export function undo( state = UNDO_INITIAL_STATE, action ) {
( key ) => ! action.transientEdits[ key ]
)
) {
// @ts-ignore we might consider using Object.assign({}, state)
nextState = [ ...state ];
nextState.flattenedUndo = {
...state.flattenedUndo,
Expand All @@ -505,6 +513,7 @@ export function undo( state = UNDO_INITIAL_STATE, action ) {

// Clear potential redos, because this only supports linear history.
nextState =
// @ts-ignore this needs additional cleanup, probably involving code-level changes
nextState || state.slice( 0, state.offset || undefined );
nextState.offset = nextState.offset || 0;
nextState.pop();
Expand Down
8 changes: 4 additions & 4 deletions packages/core-data/src/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -501,10 +501,10 @@ export const getEntityRecordNonTransientEdits = createSelector(
* Returns true if the specified entity record has edits,
* and false otherwise.
*
* @param {Object} state State tree.
* @param {string} kind Entity kind.
* @param {string} name Entity name.
* @param {number} recordId Record ID.
* @param {Object} state State tree.
* @param {string} kind Entity kind.
* @param {string} name Entity name.
* @param {number|string} recordId Record ID.
*
* @return {boolean} Whether the entity record has edits or not.
*/
Expand Down
6 changes: 4 additions & 2 deletions packages/core-data/src/utils/if-matching-action.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
/** @typedef {import('../types').AnyFunction} AnyFunction */

/**
* A higher-order reducer creator which invokes the original reducer only if
* the dispatching action matches the given predicate, **OR** if state is
* initializing (undefined).
*
* @param {Function} isMatch Function predicate for allowing reducer call.
* @param {AnyFunction} isMatch Function predicate for allowing reducer call.
*
* @return {Function} Higher-order reducer.
* @return {AnyFunction} Higher-order reducer.
*/
const ifMatchingAction = ( isMatch ) => ( reducer ) => ( state, action ) => {
if ( state === undefined || isMatch( action ) ) {
Expand Down
6 changes: 4 additions & 2 deletions packages/core-data/src/utils/replace-action.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
/** @typedef {import('../types').AnyFunction} AnyFunction */

/**
* Higher-order reducer creator which substitutes the action object before
* passing to the original reducer.
*
* @param {Function} replacer Function mapping original action to replacement.
* @param {AnyFunction} replacer Function mapping original action to replacement.
*
* @return {Function} Higher-order reducer.
* @return {AnyFunction} Higher-order reducer.
*/
const replaceAction = ( replacer ) => ( reducer ) => ( state, action ) => {
return reducer( state, replacer( action ) );
Expand Down
20 changes: 20 additions & 0 deletions packages/core-data/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"declarationDir": "build-types",
"noUnusedParameters": false,
"noImplicitAny": false
},
"references": [
{ "path": "../compose" },
{ "path": "../deprecated" },
{ "path": "../data" },
{ "path": "../element" },
{ "path": "../is-shallow-equal" },
{ "path": "../priority-queue" },
{ "path": "../redux-routine" },
{ "path": "../url" }
],
"include": [ "src/**/*.js", "src/**/*.tsx", "src/**/*.ts" ]
}
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
{ "path": "packages/block-editor" },
{ "path": "packages/components" },
{ "path": "packages/compose" },
{ "path": "packages/core-data" },
{ "path": "packages/data" },
{ "path": "packages/date" },
{ "path": "packages/deprecated" },
Expand Down

0 comments on commit 68306ab

Please sign in to comment.