Community Meeting Recap (April 12th)

Announcements

Next week’s meeting is canceled; the next OpenverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project. Weekly Development chat will be at 1500 UTC on April 26th.

Takeaways

Done

  • New version of the APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. released with thumbnail, detail, and related URLs are now HTTPSHTTPS HTTPS is an acronym for Hyper Text Transfer Protocol Secure. HTTPS is the secure version of HTTP, the protocol over which data is sent between your browser and the website that you are connected to. The 'S' at the end of HTTPS stands for 'Secure'. It means all communications between your browser and the website are encrypted. This is especially helpful for protecting sensitive data like banking information. [ref]
  • The Monitoring RFC has been approved and initial and with it, preliminary sketched out code merged [ref]
  • Added storybook visual regression tests [ref]
  • Advances in the TypeScriptification milestone [ref]
  • Improvements to the SlackSlack Slack is a Collaborative Group Chat Platform https://slack.com/. The WordPress community has its own Slack Channel at https://make.wordpress.org/chat/. notifications for the catalog [ref]

In progress

It needs review

  • Writing an RFC for a Monorepo [ref]
  • Improve the thumbnail service to support compression [ref]
  • Move media type categories to constants module [ref]
  • Several PRs for store migrationMigration Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies. to use Pinia 🍍 [ref]
  • Creation of issues for addition of new type: 3D model [ref]

It needs discussion

  • The handling and meaning of the alt_files field and extensions for audio [ref]
  • Evaluate GitHubGitHub GitHub is a website that offers online implementation of git repositories that can can easily be shared, copied and modified by other developers. Public repositories are free to host, private repositories require a paid subscription. GitHub introduced the concept of the ‘pull request’ where code changes done in branches by contributors can be reviewed and discussed before being merged be the repository owner. https://github.com/ labels [ref]

Upcoming

Priorities of stalled tickets have been adjusted, then issues labeled with critical priority will be addressed first, and then those with open milestones.

#openverse-weekly-community-meeting

Community Meeting Recap (April 5th)

Takeaways

  • We continue focusing the work on 3D model based on the 3D Model RFC.

Done

  • New OpenverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project. bot [ref]
  • Goodbye to the analytics service [ref]
  • Improvements in repo to be more friendly [ref]
  • TS improvements [ref]
  • Improvements to the provider script slackSlack Slack is a Collaborative Group Chat Platform https://slack.com/. The WordPress community has its own Slack Channel at https://make.wordpress.org/chat/. notification [ref]
  • Apt upgrade issue in the catalog [ref]
  • Fixed of a CSRF issue [ref]
  • Fixed of an issue with black dependency [ref]

In progress

It needs review

  • Fixing focus-visible in Safari [ref]
  • TS-ification and refactoring [ref]
  • Adding Sketchfab and Thingiverse as additional sources for 3D models [ref]
  • Adding a timeout to the @_loop recipe [ref]
  • Reducing flakiness of just init [ref]
  • Updates in the ingestion server [ref]
  • Adding types to basic components [ref]

It needs discussion

  • Move media type categories to constants module [ref]
  • Filtering audio by extension [ref]

Upcoming

  • More feedback on the feature flags RFC
  • Creating issues for the 3D model integration.

#openverse-weekly-community-meeting

Community Meeting Recap (March 29th)

Takeaways

  • Next week, the team is going to begin focusing more intently on 3D model support, following the 3D Model RFC.
  • Our Monitoring RFC could use additional review.
  • Moving forward, our plan is to generally follow an every-two-weeks release schedule.

Done

In progress

High priority issues for triage/fixing

#openverse-weekly-community-meeting

A week in Openverse: 2022-03-21 – 2022-03-28

openverse

Merged PRs

  • #202: Update feature_request.md label template to remove priority and aspect
  • #198: Update bug_report.md to remove default priority label
  • #197: Update bug_report.md to remove `Expectation` section
  • #194: Add infrastructure repo to synced repo list

Closed issues

  • #157: Create OpenverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project. GitHubGitHub GitHub is a website that offers online implementation of git repositories that can can easily be shared, copied and modified by other developers. Public repositories are free to host, private repositories require a paid subscription. GitHub introduced the concept of the ‘pull request’ where code changes done in branches by contributors can be reviewed and discussed before being merged be the repository owner. https://github.com/ activity overview dashboard
  • #140: Remove “Expectation” headerHeader The header of your site is typically the first thing people will experience. The masthead or header art located across the top of your page is part of the look and feel of your website. It can influence a visitor’s opinion about your content and you/ your organization’s brand. It may also look different on different screen sizes. from bug report template
  • #73: [Feature] Configure ESLint and Prettier for JS scripts
  • #31: [MetaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress.] 3D Models
  • #30: Remove requests for reviews from closed PRs

openverse-catalog

Merged PRs

  • #441: 🔄 Synced file(s) with WordPress/openverse
  • #440: 🔄 Synced file(s) with WordPress/openverse
  • #424: Add LRU cache to `is_valid_license_info`
  • #423: Change PhyloPic date range & schedule interval
  • #422: Round duration for provider ingestion completion message
  • #421: Enable XCom pickling in Airflow
  • #397: Add data refresh to Airflow

Closed issues

  • #419: Add an `lru_cache` to `is_valid_license_info`
  • #410: Change Phylopic to @weekly
  • #377: Enable XCom pickling
  • #373: Format “Airflow DAG Load Data Complete” duration
  • #353: Data refresh orchestration DAG

openverse-api

Merged PRs

  • #591: 🔄 Synced file(s) with WordPress/openverse
  • #590: 🔄 Synced file(s) with WordPress/openverse
  • #586: 🔄 Synced file(s) with WordPress/openverse
  • #584: Replace plural `categories` as field name with singular `categoryCategory The 'category' taxonomy lets you group posts / content together that share a common bond. Categories are pre-defined and broad ranging.`
  • #583: Replace plural `categories` as field name with singular `category`
  • #580: Add CI check for uncommitted migrations
  • #577: Remove `query_serializer` for reporting endpoints
  • #576: Use `httpsHTTPS HTTPS is an acronym for Hyper Text Transfer Protocol Secure. HTTPS is the secure version of HTTP, the protocol over which data is sent between your browser and the website that you are connected to. The 'S' at the end of HTTPS stands for 'Secure'. It means all communications between your browser and the website are encrypted. This is especially helpful for protecting sensitive data like banking information.` for hyperlinked APIs by replacing the URLs

Closed issues

  • #573: Return secure URLs for the fields thumbnail, detail_url and related_url.
  • #571: Run `makemigrations` in CI to prevent merging PRs with missing migrations.

openverse-frontend

Merged PRs

  • #1187: 🔄 Synced file(s) with WordPress/openverse
  • #1186: Mock services using jest.mock
  • #1183: 🔄 Synced file(s) with WordPress/openverse
  • #1182: Fix missing nuxt types
  • #1178: Add useFetchState composable
  • #1175: Add the 3D model SVG
  • #1173: Remove redundant type and simplify media service
  • #1172: Content page component design fixes
  • #1168: Update audio categories
  • #1166: Remove source links from sources page
  • #1163: Add support for TypeScript in VueVue Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. https://vuejs.org/. SFCs.
  • #1153: Add local visual regression infrastructure
  • #1150: Typescriptify `api-service`
  • #1148: Hotfix for negative values in peaks
  • #1147: Strictly filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. sentry errors
  • #1144: Enable HTTPS in local development
  • #1142: fix focus outline placement button
  • #1140: Fix hero search button layout error
  • #1139: Add import extension linting rule
  • #1134: Convert license utils and constants to TS
  • #1131: Use links instead of buttons for header search type switcher
  • #1040: Convert the search store to Pinia

Closed issues

  • #1169: Audio category filter not working correctly
  • #1149: Add types to `data/api-service`
  • #1145: Add sentry ignore filters
  • #1143: Enable https in local development
  • #1138: Enable `import/extensions` rule for ESLint
  • #1136: Layout error in the hero search button in some locales
  • #1130: Search type switcher items in the header should use a link instead of a button
  • #1128: Europeana and SoundCloud don’t support search filters
  • #1122: Add 3D model icon svg to the project
  • #1121: Reduce to a single source of truth for search filters
  • #1110: Fix play/pause button focus outline placement
  • #1090: Create `VContentPage` component
  • #1037: Convert `search` store from Vuex to Pinia
  • #1019: Configure CI to run visual regression tests
  • #1017: Configure local visual regression testing
  • #1008: Providers links from Source page not working properly
  • #931: Include `utils/license.js` in `tsconfig.jsonJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML.`

#openverse, #week-in-openverse

Community Meeting Recap (Mar 22nd)

Takeaways

Done

In progress

  • All media grid is nearly ready, except a few small bugs [ref]
  • HTTPSHTTPS HTTPS is an acronym for Hyper Text Transfer Protocol Secure. HTTPS is the secure version of HTTP, the protocol over which data is sent between your browser and the website that you are connected to. The 'S' at the end of HTTPS stands for 'Secure'. It means all communications between your browser and the website are encrypted. This is especially helpful for protecting sensitive data like banking information. in APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. hyperlinks [ref]
    • PR#574 proxies using NGINXNGINX NGINX is open source software for web serving, reverse proxying, caching, load balancing, media streaming, and more. It started out as a web server designed for maximum performance and stability. In addition to its HTTP server capabilities, NGINX can also function as a proxy server for email (IMAP, POP3, and SMTP) and a reverse proxy and load balancer for HTTP, TCP, and UDP servers. https://www.nginx.com/. (changes requested)
    • PR#576 rewrites URLs (merged)
  • RFCs
  • TSification [ref]
  • HTTPS in frontend dev [ref]
  • Monorepo discussion [ref]
  • Making Overvue and the Openverse Slack integration official [ref]
  • Focus-visible in Safari is not working [ref]

High priority issues for triage/fixing

#openverse-weekly-community-meeting

A week in Openverse: 2022-03-14 – 2022-03-21

openverse

Merged PRs

  • #171: RFC: 3D Model Support

openverse-catalog

Merged PRs

  • #418: Fix invalid license urls from Finnish Museum APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways.
  • #417: Use published Docker image in primary docker-compose.yml
  • #416: Fix schedule intervals on Cleveland Museum & Wikimedia Commons
  • #415: Reduce noise in NYPL ingestion
  • #414: Update API requests for Museum Victoria DAG
  • #413: Add ConnectionError to acceptable flaky exceptions for Freesound
  • #412: Add OFEO-SG subprovider
  • #409: Group test runs by module or class
  • #404: 🔄 Synced file(s) with WordPress/openverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project.
  • #402: Make ‘sound’ categoryCategory The 'category' taxonomy lets you group posts / content together that share a common bond. Categories are pre-defined and broad ranging. more specific
  • #395: Handle duplicate keys in load_data task

Closed issues

  • #408: Group tests by test class in pytest to prevent test collisions
  • #406: Smithsonian workflow is missing configuration for sub-providers
  • #401: NYPL provider script is noisy regarding missing primary creators
  • #392: Finnish Museum `pull_data` freezes and times out
  • #391: PhyloPic DAG detects no content even when data exists
  • #390: Museum Victoria DAG fails to pull data
  • #389: Freesound pull_data task fails when getting audio file size
  • #388: Handle duplicate keys in the TSV load_data task
  • #379: Change Wikimedia Commons schedule interval to @daily
  • #378: Use published Docker image in primary docker-compose.yml
  • #368: Rename the “ingestion server” to “data refresh”

openverse-api

Merged PRs

  • #570: Add missing migrations
  • #568: Add throttle exemptions
  • #566: 🔄 Synced file(s) with WordPress/openverse
  • #556: Add pronunciation as valid sound category
  • #554: Add parameter to exclude certain sources

Closed issues

  • #565: Create an unrestricted rate limit model
  • #553: Query param to exclude a source
  • #526: Sound category mismatch
  • #391: Monitoring all the things

openverse-frontend

Merged PRs

  • #1137: Remove lodash.findindex from dependencies
  • #1129: Fix audio track null duration and add defaultRef
  • #1120: Update tailwindcss-rtl, talkback and typescript
  • #1115: 🔄 Synced file(s) with WordPress/openverse
  • #1112: Tweaks to the Image Details page
  • #1098: Fix mature content report submission
  • #1072: Refactor media store results getters
  • #1058: Convert more utils to TypeScript
  • #1057: Run e2e tests inside a docker container

Closed issues

  • #1111: Wrong font size on image details page and has horizontal scrolling on mobile
  • #1106: Replace `lodash.isempty` with domain-specific implementation
  • #1105: Replace `lodash.findindex` with `Array.prototype.findIndex`
  • #1079: Mature content report submission is broken
  • #1076: Audio track current time sometimes being set to non-real number
  • #1056: Faulty logic for audio count on the all results view
  • #1030: Audit tree-shaking and dead-code removal when using environment flags from `node_env.ts`
  • #929: Add types to `utils/get-parameter-by-name.js`
  • #920: Add types to `utils/attribution-html.js`
  • #895: Homepage search button text doesn’t fit in some locales
  • #756: Switch to Pinia

openverse-browser-extension

Merged PRs

  • #32: 🔄 Synced file(s) with WordPress/openverse

#openverse, #week-in-openverse

Community Meeting Recap (Mar 15th)

Takeaways

Done

  • Changes to the sound categoryCategory The 'category' taxonomy lets you group posts / content together that share a common bond. Categories are pre-defined and broad ranging. [ref]
  • A11yAccessibility Accessibility (commonly shortened to a11y) refers to the design of products, devices, services, or environments for people with disabilities. The concept of accessible design ensures both “direct access” (i.e. unassisted) and “indirect access” meaning compatibility with a person’s assistive technology (for example, computer screen readers). (https://en.wikipedia.org/wiki/Accessibility) fix for a double ring on focus around icon buttons by a new contributor 🎉 [ref]
  • Pinia migrationMigration Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies. PRs [ref]
  • TypeScript migration PRs [ref, ref]
  • Talkback proxy changes [ref]
  • Removal of the usage analytics code [ref]
  • Caching the audio waveforms in the APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. [ref]
  • Update of Django to version 4 in the API [ref]

In Progress

  • End-to-end test dockerization PR needs a second review [ref]
  • Add parameter to exclude certain sources in the API [ref]
  • Fix mature content report submission [ref]
  • Tweaks to the Image Details page [ref]
  • Convert more utils to TypeScript [ref]

Upcoming

  • Unrestricted rate limit model [ref]
  • Add 3D models as an “additional source” (metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. search only view) in the content switcher [ref]
  • Addition of model_3d meta sources [ref]
  • Addition of video as a meta source [ref]

#openverse, #openverse-weekly-community-meeting

A week in Openverse: 2022-03-07 – 2022-03-14

openverse

Merged PRs

  • #191: Label PRs by contributors
  • #189: Update Pipenv files for Python 3.10
  • #188: Update Python workflows to run on Python 3.10
  • #185: Prevent PR labeller from overwriting labels on labelled PRs
  • #184: Lint RFCs and ensure they are lint-checked in the future
  • #180: Create a workflow to label a PR based on its linked issues

Closed issues

  • #183: Update Python workflows to run on Python 3.10
  • #175: PRs created with labels via GH CLICLI Command Line Interface. Terminal (Bash) in Mac, Command Prompt in Windows, or WP-CLI for WordPress. fail label check
  • #75: [Feature] Automatically label PRs with the aspect and goal labels

openverse-catalog

Merged PRs

  • #403: 🔄 Synced file(s) with WordPress/openverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project.

Closed issues

  • #384: Update APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. key for NYPL DAG
  • #383: Update API key for Smithsonian DAG

openverse-api

Merged PRs

  • #563: Send `[]` if media has no tags
  • #555: 🔄 Synced file(s) with WordPress/openverse
  • #548: Bump django from 3.2.12 to 4.0.3 in /api
  • #536: Bump pytest from 6.2.5 to 7.0.1 in /analytics
  • #530: Django command for generating waveforms

Closed issues

  • #549: Upgrade to Django 4
  • #529: Audio waveform cache-warming Django command
  • #143: [Bug] Integration tests of Ingestion server are failing

openverse-frontend

Merged PRs

  • #1113: Removed unused css class transition-colors
  • #1109: Remove unused deps
  • #1100: Handle waveform with `peaks` prop as a blank array
  • #1099: Add component imports, remove extra blank lines between imports
  • #1097: Remove Vocabulary icon font
  • #1095: Move typography defaults into `tailwind.css` file
  • #1092: Switch to css grid instead of legacy column classes in media reuse
  • #1084: Remove analytics code
  • #1082: Update a11yAccessibility Accessibility (commonly shortened to a11y) refers to the design of products, devices, services, or environments for people with disabilities. The concept of accessible design ensures both “direct access” (i.e. unassisted) and “indirect access” meaning compatibility with a person’s assistive technology (for example, computer screen readers). (https://en.wikipedia.org/wiki/Accessibility) pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party and remove outdated package
  • #1080: 🔄 Synced file(s) with WordPress/openverse
  • #1070: Fix prop name mismatch
  • #1069: removing all the ‘ focus: ‘ classes from VIconButton.vue
  • #1068: Add Centre for Ageing to image metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. search
  • #1065: Give clearer feedback for how to fix outdated POT file in CI
  • #1063: Removed iframeiframe iFrame is an acronym for an inline frame. An iFrame is used inside a webpage to load another HTML document and render it. This HTML document may also contain JavaScript and/or CSS which is loaded at the time when iframe tag is parsed by the user’s browser.-height.js and its implementations
  • #1061: Convert Pinia stores to TypeScipt
  • #1045: Use a non-versioned API URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org to mock analytics requests, too
  • #1039: Extract filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. store from the search store and convert it to Pinia

Closed issues

  • #1094: Add font defaults to tailwind css file
  • #1091: Media reuse uses legacy columns classes
  • #1074: Empty waveform peaks data renders an empty waveform; should render placeholder instead.
  • #1067: Meta search provider: Centre for Ageing Better
  • #1059: Remove dead iframe height code
  • #1054: Replace individual `lodash.*` packages with `lodash` or remove entirely
  • #1026: Convert `usage-data` store from Vuex to Pinia
  • #1025: Convert `user` store from Vuex to Pinia
  • #1009: Empty audio search page shows audio track skeletons indefinitely
  • #1005: Audio play buttons have double focus rings
  • #1003: TypeError: Cannot read properties of undefined (reading ‘name’)
  • #919: Search from error page only show images
  • #915: Mock e2e testing analytics network requests
  • #842: Only update POT file timestamp if translations have changed
  • #834: Fixed footer when loading more images
  • #799: Image results sometimes `undefined`

openverse-browser-extension

Merged PRs

  • #31: Update README.md for consistiency with other repos
  • #29: 🔄 Synced file(s) with WordPress/openverse

Closed issues

  • #30: Update README to match other repositories

#openverse, #week-in-openverse

Openverse Frontend v3.1.1 Release

This week we released an update to the OpenverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project. frontend! This release included many improvements from our redesign launch in January. I’ll showcase a few of those here, and you can read the full release notes for more details. In total, there were over 64 bug fixes alongside some of these new features.

Content chooser on the mobile homepage

Prior to this release, mobile users weren’t able to select their desired content type on the homepage. They were only able to search ‘all results’.

Now they can choose their desired media type with large touch-friendly buttons.

Please don’t needlessly report cute puppies!

Redesigned content reporting flow

Our content reporting flow was redesigned to be simpler, more accessible, and easier for users.

New Image detail pages

Our image detail page was completely redesigned, and showcases images front and center.

Skip to content button

We now have a ‘Skip to Content’ button as the first focusable element on our pages for improved accessibilityAccessibility Accessibility (commonly shortened to a11y) refers to the design of products, devices, services, or environments for people with disabilities. The concept of accessible design ensures both “direct access” (i.e. unassisted) and “indirect access” meaning compatibility with a person’s assistive technology (for example, computer screen readers). (https://en.wikipedia.org/wiki/Accessibility).

Thanks to all of the Openverse team members who worked on and provided code review for these issues.

TypeScript is now a first class citizen in Openverse frontend

Well, mostly

As of the merging of this PR in the WordPress/openverse-frontend repository, it is now possible to use native TypeScript for a lot of the code in OpenverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project. for which we were previously using JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com/.. The only exception to this are VueVue Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. https://vuejs.org/. single-file-components (SFCs)1. We will continue to use regular JavaScript with helpful but non-contractual2 JSDoc annotations in Vue SFCs; for the rest of our JavaScript we will slowly add type-checking via one of the two methods described below.

There are now two ways to add types to any given module. You can either:

  1. Include the JavaScript module directly in the tsconfig.json includes array, as has been done with use-event-listener-outside.js on this line. This prompts TypeScript to rely on JSDoc type annotations to type-check regular JavaScript.
  2. Rename the file from .js to a .ts. All TypeScript files are automatically included in our tsconfig.json and will be type-checked.

Please note, the second will require restarting your dev server as Webpack won’t be able to keep track of file extensions changing (it’ll get stuck looking for a now non-existent *.js file).

In general, the current contributors to Openverse’s frontend prefer to use native TypeScript over the JSDoc variant. In particular more of us know native TypeScript syntax than the intricacies of the JSDoc variant.

There is a Milestone in the WordPress/openverse-frontend repository to track progress on adding type checking to all the modules that would allow it. If you work on these issues, please note that it is best practice to reduce the number of runtime changes to the module when converting them to TypeScript; however, sometimes it is necessary to add additional runtime type-checks to satisfy the TypeScript compiler. Anticipate needing to do this.

Some specific techniques to keep in mind

There are some specific techniques I’ve found helpful for gradually adding TypeScript to an existing JavaScript project; in particular, much of this was learned during the ongoing effort to add type-checking to GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/ and its various packages.

Discriminated union type narrowing

This technique is useful when you get a discriminated union type from a function return and need to prove to TypeScript that you know what the type of the object is you’re working with. For example, take our MediaDetail type. Perhaps you have an array typed MediaDetail[] and would like to iterate over each and do something different with each media type.

The way to do this is to use the MediaDetail‘s shared frontendMediaType property. The presence of this property is what makes the MediaDetail type a discriminated (or “tagged”) union: the value of the frontendMediaType property allows the type checker to discriminate between the possible types that can be assigned to a MediaDetail. For example, because frontendMediaType on AudioDetail is typed as the string constant 'audio', the type checker will know that the following assertion will narrow the type of the object to the AudioDetail type:

const mediaDetails: MediaDetail[] = getMediaDetailArray()

mediaDetails.forEach((mediaDetail) => {
  if (mediaDetail.frontendMediaType === 'audio') {
    // In here, TypeScript will know that mediaDetail is an AudioDetail type
  } else {
    // Because MediaDetail can only by AudioDetail or ImageDetail (for now), in here TS will know that mediaDetail is an ImageDetail type
  }
})

Here is an example of the above in the TypeScript playground for you to play around with.

Type assertion functions

Sometimes we need to assert the type of something that is not starting from a discriminated union type. For example, variables typed as unknown need to be cast to a known type before properties on them can be accessed. To do this, we can use a type assertion function.

Note: Before getting too deep in the weeds of this tool, please keep in mind that under the hood a type assertion function is essentially a hard cast that is theoretically backed by a runtime “type check” (where type here usually refers to shaped types rather than nominal types). That means that there’s effectively no difference between a type assertion function and foo as unknown as WhateverIWant. TypeScript is going to take our word that our type assertion functions actually do the work to “prove” (in so far as types are provable in TypeScript) that we have the type we say we have. That means that we should carefully consider how we use this tool and also ensure that we cover the implementing functions with 100% unit test coverage. TypeScript will gladly accept the following function as a boolean type assertion, despite it being nonsense:

function isBoolean(o: any): o is boolean {
return typeof o === 'string'
}

So be careful! Anyway, back to the show…

The TypeScript project has a playground that describes this feature here. It’s kind of wordy, so I’ll summarize it here.

Essentially, if you can prove to yourself via some runtime type checks that a variable is a specific type, then you can let TypeScript know this through a special is return type annotation.

const isNumber = (o: any): o is number => typeof o === 'number'

That’s the simplest example. A more complex example could be the following:

const isPromise = (o: any): o is Promise => {
return (
o &&
typeof o.then === 'function' &&
typeof o.catch === 'function' &&
typeof o.finally === 'function'
)
}

You may also use the special keyword asserts to indicate to TypeScript that the function will stop execution in the parent context (probably by throwing an error but it could also be via process.exit in a Node context) if the runtime type check does not pass.

This is useful when you know code needs to fail to execute if a value is null or undefined for example:

export function assertIsDefined(val: T): asserts val is NonNullable {
if (typeof val === 'undefined' || val === null) {
throw new Error()
}
}

When you use this function, after calling assertIsDefined(foo), TypeScript will know that foo is not null or undefined.

Casting to const

Casting to const is an invaluable tool in TypeScript as it allows you to derive specific types from object and array definitions rather than general types. If you want to declare an array a tuple in TypeScript, you must use the as const cast.

const generalStringArray = ['one', 'two', 'three']

const tuple = ['one', 'two', 'three'] as const

The generalStringArray will have the inferred type of string[] where as tuple will have the much more specific type of ['one', 'two', 'three'] (literally, the type will be the same as the value, how amazing is that?!).

This is particularly useful (and in fact necessary) to use for typing a dependency array for the watch function. Without casting the dependency array to const, TypeScript will infer a mixed type for each element of the array passed to the watcher callback that combines all the constituent parts of the dependencies.

Please open this TypeScript playground link to see a live example of this problem and how to solve it by casting to const. Note how in the first watch example, each of the values in the callback are typed as a combination of the types of each element of the dependency array. In the second, which uses as const, TypeScript is told to determine the type of the values in the callback by position as in a tuple where each element is typed separate from the others.

Packages to know about

@types/nuxt

This package is already included in our dependencies and houses all of the various Nuxt types like the type for context and app. Extending the types in this package via interface merging allows us to describe our additional modifications to Nuxt’s context. For example, we currently add annotations for the $ua and i18n extensions to Nuxt’s context. When typing anything that uses the useContext composable, it may be necessary to add further extensions to those types.

vue

This is of course one of the coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. packages of our frontend application. It also houses many core types for Vue, like the Component type.

@nuxtjs/composition-api

You likely already are aware of this package, but please note that it includes a wealth of Vue related types for the Composition APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways.. In here you will find the Ref type for example.

utility-types

The utility-types package includes a helpful set of types for dealing with common TypeScript scenarios. This is not currently included in our dependencies but is a reliable source of utility types should we need them. Check this package first before trying to write super-complex generic mapped types.

More helpful resources

TypeScript playground

The TypeScript playground (https://www.typescriptlang.org/play) is very helpful for collaborating with others on type-related problems. I’ve found it particularly helpful in that it forces me to narrow the problem I’m having to the bare-minimum example of it. Often times this practice alone can help me resolve an issue I’m having or at least see it more clearly.

Type challenges

If you’re looking to flex new, growing, or even strong TypeScript muscles, the type-challenges repository is a great resource. It’s a collection of small (though almost never simple) TypeScript challenges that force you to explore things like type inference, generic types, mapped types, and other intermediate to advanced TypeScript features.

I will say that even some of the so-called “easy” challenges are not for the faint of heart! They can be quite the brain teasers and sometimes pretty frustrating but so satisfying to find solutions for. The community is also quite active in sharing their solutions and this is a great way to pick up new tricks from TypeScript wizards.


1 There’s a little bit more tooling we’d have to do to get Vue files able to be typed, in particular around distinguishing Vue templates from ReactReact React is a JavaScript library that makes it easy to reason about, construct, and maintain stateless and stateful user interfaces. https://reactjs.org/. JSX (it appears TypeScript gets quite confused about this). Storybook, unfortunately, is the culprit here as its dependencies pull in the @types/react package which pollutes (at least from a Vue perspective) the global JSX namespace with React specific types. For example, React’s type for the class attribution on an HTMLHTML HTML is an acronym for Hyper Text Markup Language. It is a markup language that is used in the development of web pages and websites. element does not allow for Vue’s array and object classname binding syntax. One solution would be to switch to the vue-tsc library, and indeed we will do that when time comes for us to upgrade Nuxt via Nuxt bridge; but for now plain old TypeScript is fine for our purposes.

2 I use the phrase “helpful but non-contractual” here to distinguish from the “contractual” aspect of actually type checking a file. The JSDoc annotations in SFCs are helpful to indicate to the reader (and likely to their editor) what the intention is; but they are non-contractual in that they are not checked for correctness or enforced by the TypeScript compiler. You may still notice some editors giving you TypeScript errors in this file (VSCode will do this, for example) but they will not be enforced by the CI type-checking.