diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index aa493c7dcd997d..ef10d8c4c36298 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -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_ diff --git a/packages/core-data/README.md b/packages/core-data/README.md index 2dc7df4a04d71e..fd7f795b5d900a 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -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_ diff --git a/packages/core-data/src/batch/default-processor.js b/packages/core-data/src/batch/default-processor.js index 34f38ff5c3d0da..d4189550605652 100644 --- a/packages/core-data/src/batch/default-processor.js +++ b/packages/core-data/src/batch/default-processor.js @@ -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', diff --git a/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js b/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js index 09248d2102cda3..bb1bf41d9e2cda 100644 --- a/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js +++ b/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js @@ -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 */ /** @@ -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 * @@ -82,6 +93,7 @@ const fetchLinkSuggestions = async ( const { disablePostFormats = false } = settings; + /** @type {Promise[]} */ const queries = []; if ( ! type || type === 'post' ) { @@ -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( @@ -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, + }; + } ); } ); }; diff --git a/packages/core-data/src/reducer.js b/packages/core-data/src/reducer.js index b4034087bf696d..f0f93b111234d8 100644 --- a/packages/core-data/src/reducer.js +++ b/packages/core-data/src/reducer.js @@ -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 @@ -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( [ @@ -406,7 +408,11 @@ export const entities = ( state = {}, action ) => { /** @typedef {Array & 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} */ @@ -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. */ @@ -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 ); @@ -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, @@ -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(); diff --git a/packages/core-data/src/selectors.js b/packages/core-data/src/selectors.js index 67cd6b1aa5087e..279fd032d8581b 100644 --- a/packages/core-data/src/selectors.js +++ b/packages/core-data/src/selectors.js @@ -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. */ diff --git a/packages/core-data/src/utils/if-matching-action.js b/packages/core-data/src/utils/if-matching-action.js index bbbe35800187bd..022c4211a8a284 100644 --- a/packages/core-data/src/utils/if-matching-action.js +++ b/packages/core-data/src/utils/if-matching-action.js @@ -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 ) ) { diff --git a/packages/core-data/src/utils/replace-action.js b/packages/core-data/src/utils/replace-action.js index 91cecb0e391513..92f22c22dd1bff 100644 --- a/packages/core-data/src/utils/replace-action.js +++ b/packages/core-data/src/utils/replace-action.js @@ -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 ) ); diff --git a/packages/core-data/tsconfig.json b/packages/core-data/tsconfig.json new file mode 100644 index 00000000000000..35d05d8fa3b033 --- /dev/null +++ b/packages/core-data/tsconfig.json @@ -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" ] +} diff --git a/tsconfig.json b/tsconfig.json index 8a78ab8e69a83a..8486f2dba941b7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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" },