Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataViews: Enable types #61185

Merged
merged 2 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
/**
* Internal dependencies
*/
import type { Field } from './types';

/**
* Apply default values and normalize the fields config.
*
* @param {Object[]} fields Raw Fields.
* @return {Object[]} Normalized fields.
* @param fields Fields config.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the type missing here?

Copy link
Contributor Author

@youknowriad youknowriad Apr 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, in typescript, it's not needed because it's actually defined as part of the code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I hadn't noticed the file had been switched to TS. Do we need to switch our code to TypeScript for us to use the TS types in the docs? I thought we could use them in the JSDoc directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oandregal you can use them in JSDocs. I switched to typescript extension because I didn't want to list all the JS files that are fully type-checked in tsconfig file. the tsconfig file only targets all "ts" files for now.

* @return Normalized fields config.
*/
export function normalizeFields( fields ) {
export function normalizeFields( fields: Field[] ): Field[] {
return fields.map( ( field ) => {
const getValue = field.getValue || ( ( { item } ) => item[ field.id ] );

Expand Down
79 changes: 79 additions & 0 deletions packages/dataviews/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* External dependencies
*/
import type { ReactNode } from 'react';

type Item = Record< string, any >;

interface Option {
value: any;
label: string;
}

interface filterByConfig {
operators?: string[];
isPrimary?: boolean;
}

export interface Field {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried looking at all of our existing "fields" to define this. It might not be 100% accurate yet. We're also lacking the enumerations for available types and operators but it's a decent start.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with this package so this may be off base.

There's an alternative to defining a single interface that all the instances "fit," which is to make this a union of very specific types. If there's a specific set of known fields, a discriminated union can be more expressive and provide much more precise and relevant to developers working with the code.

// Instead of
interface Field {
  id: string;
  getValue?: ( obj: any ) => any;
}

// A union can be more expressive:
type FieldUnion =
  | { id: "countField"; getValue( field: { items: Array<any> } ) => number; }
  | { id: "dateField"; getValue( field: { date: Date } ) => string; };

Something to consider. I also wrote a longer form post about the idea.

/**
* The unique identifier of the field.
*/
id: string;

/**
* The label of the field. Defaults to the id.
*/
header?: string;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should rename this one "label". header is too "table" specific wording.


/**
* Callback used to retrieve the value of the field from the item.
* Defaults to `item[ field.id ]`.
*/
getValue?: ( { item }: { item: Item } ) => any;

/**
* Callback used to render the field. Defaults to `field.getValue`.
*/
render?: ( { item }: { item: Item } ) => ReactNode;

/**
* The width of the field column.
*/
width?: string | number;

/**
* The minimum width of the field column.
*/
maxWidth?: string | number;

/**
* The maximum width of the field column.
*/
minWidth?: string | number;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have three different "width" properties. It felt too much for me. Do we really need all of these.


/**
* Whether the field is sortable.
*/
enableSorting?: boolean;

/**
* Whether the field is searchable.
*/
enableGlobalSearch?: boolean;

/**
* Whether the field is filterable.
*/
enableHiding?: boolean;

/**
* The list of options to pick from when using the field as a filter.
*/
elements?: Option[];

/**
* Filter config for the field.
*/
filterBy?: filterByConfig;
}
20 changes: 20 additions & 0 deletions packages/dataviews/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Came here to suggest that we should add a types: "build-types" in dataviews' package.json file, but it turns out we already have it. Not sure what whether there's any side-effects this could have (not having types vs having types after this PR), but thought worth mentioning it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No important impact aside that third-party devs using the package will now see some types appearing (autocompletion and all) when they use the package. Previously the build-types folder was empty, now it has the types defined in this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @wordpress/dataviews/build-types/ folder has the proper data (types + TS files).

Though I'm a bit confused. I wanted to see what we had previously, so I went to trunk and did npm install && npm run build. Prior to that, I removed everything (tried in a few different ways: manually rm -rf node_modules, as well as other options npm run distclean or npm run clean:*). The @wordpress/dataviews/build-types folder contained the types and TS files from this PR 😕 I presume there's a cache somewhere I'm not clearing. It'd be nice to learn how to clear this. Other than that, I suspect it's working as expected.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right I have the same issue. I think the problem is that "dataviews" is not on the root tsconfig.json file in trunk which means when running npm run clean:package-types, typescript doesn't touch it at all, it's not aware of its existence so it's not cleared.

"$schema": "https://json.schemastore.org/tsconfig.json",
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"declarationDir": "build-types"
},
"references": [
{ "path": "../a11y" },
{ "path": "../components" },
{ "path": "../compose" },
{ "path": "../element" },
{ "path": "../i18n" },
{ "path": "../icons" },
{ "path": "../keycodes" },
{ "path": "../primitives" },
{ "path": "../private-apis" }
],
"include": [ "src/**/*.ts", "src/**/*.tsx" ]
Comment on lines +4 to +19
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like the preferred way of including src but not typechecking *.js files:

Suggested change
"compilerOptions": {
"rootDir": "src",
"declarationDir": "build-types"
},
"references": [
{ "path": "../a11y" },
{ "path": "../components" },
{ "path": "../compose" },
{ "path": "../element" },
{ "path": "../i18n" },
{ "path": "../icons" },
{ "path": "../keycodes" },
{ "path": "../primitives" },
{ "path": "../private-apis" }
],
"include": [ "src/**/*.ts", "src/**/*.tsx" ]
"compilerOptions": {
"rootDir": "src",
"declarationDir": "build-types",
"checkJs": false
},
"references": [
{ "path": "../a11y" },
{ "path": "../components" },
{ "path": "../compose" },
{ "path": "../element" },
{ "path": "../i18n" },
{ "path": "../icons" },
{ "path": "../keycodes" },
{ "path": "../primitives" },
{ "path": "../private-apis" }
],
"include": [ "src" ]

I think there's an ongoing problem with react and ariakit types that I expect to be fixed by #60796. Sometimes I get errors like this:

node_modules/@ariakit/react-core/cjs/tooltip/tooltip-provider.d.ts:14:100 - error TS2694: Namespace '"…/node_modules/@types/react/jsx-runtime"' has no exported member 'JSX'.

14 export declare function TooltipProvider(props?: TooltipProviderProps): import("react/jsx-runtime").JSX.Element;

We can work around that in this PR if its a problem by adding "skipLibCheck": true to the compilerOptions.

}
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
{ "path": "packages/compose" },
{ "path": "packages/core-data" },
{ "path": "packages/data" },
{ "path": "packages/dataviews" },
{ "path": "packages/data-controls" },
{ "path": "packages/date" },
{ "path": "packages/deprecated" },
Expand Down
Loading