<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Joe Flateau</title>
    <description>The latest articles on DEV Community by Joe Flateau (@joeflateau).</description>
    <link>https://dev.to/joeflateau</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F118671%2F9cf9222e-857c-4386-9e35-cbed5056bdc2.jpeg</url>
      <title>DEV Community: Joe Flateau</title>
      <link>https://dev.to/joeflateau</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joeflateau"/>
    <language>en</language>
    <item>
      <title>Creating custom TypeORM Operators</title>
      <dc:creator>Joe Flateau</dc:creator>
      <pubDate>Thu, 11 Nov 2021 18:14:10 +0000</pubDate>
      <link>https://dev.to/joeflateau/creating-custom-typeorm-operators-36oh</link>
      <guid>https://dev.to/joeflateau/creating-custom-typeorm-operators-36oh</guid>
      <description>&lt;p&gt;I spent an hour or two today trying to create a custom TypeORM &lt;code&gt;FindOperator&lt;/code&gt;. I found a few results searching Google but all of them seem to be outdated and don’t work with the current release of TypeORM. Ultimately the solution was so easy, almost too easy.&lt;/p&gt;

&lt;p&gt;I wanted to create a TypeORM operator for the &lt;a href="https://www.postgresql.org/docs/9.3/functions-matching.html#FUNCTIONS-POSIX-TABLE"&gt;Postgres Regex Match Operator&lt;/a&gt;. My first approach was to subclass FindOperator and override &lt;code&gt;toSql&lt;/code&gt; which seems to now be called &lt;code&gt;getSql&lt;/code&gt;. But that did not work (seems TypeORM ignores that now and builds the query based on the &lt;code&gt;type&lt;/code&gt; property instead.) That’s probably the right thing to do because it allows them to implement operators differently based on the type of database TypeORM is connecting to. But that doesn’t help me, I just need PostgreSQL. So without further ado, here’s my solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Raw } from "typeorm";

let uid = 0;
export function RegexMatches(regex: string) {
  const paramId = `regex${uid++}`;
  return Raw((pathAlias: string) =&amp;gt; `${pathAlias} ~ :${paramId}`, {
    [paramId]: regex,
  });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yep, just wrap the &lt;code&gt;Raw&lt;/code&gt; operator and output the condition that you want to match. In my case, the &lt;code&gt;~&lt;/code&gt; Regex (case sensitive) Match operator. TypeORM escapes the path alias for you and your regex is passed as a parameter, so no problems with SQL injection here if your regex is built dynamically. The parameter name used must be unique if we want to use the operator more than once in a query, so we’ll create a unique id for that.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Extending express request/response objects in Typescript</title>
      <dc:creator>Joe Flateau</dc:creator>
      <pubDate>Fri, 01 Nov 2019 03:49:01 +0000</pubDate>
      <link>https://dev.to/joeflateau/extending-express-request-response-objects-in-typescript-kln</link>
      <guid>https://dev.to/joeflateau/extending-express-request-response-objects-in-typescript-kln</guid>
      <description>&lt;p&gt;It’s useful to be able to provide a unified response “envelope” when creating a REST API. This envelope can contain metadata, data and information on errors and warnings.&lt;/p&gt;

&lt;p&gt;To do so with &lt;code&gt;express&lt;/code&gt; for nodejs you can add custom functions to the &lt;code&gt;request&lt;/code&gt; prototype and declare them in a module augmentation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { response } from "express";

// augment the `express-serve-static-core` module
declare module "express-serve-static-core" {
  // first, declare that we are adding a method to `Response` (the interface)
  export interface Response {
    respondWithData(data: any): this;
  }
}

// now actually add it to `response` (the prototype)
response.respondWithData = function(data) {
  return this.json({ errors: null, data: data });
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Possibly confusing:&lt;/p&gt;

&lt;p&gt;The value &lt;code&gt;request&lt;/code&gt; imported from &lt;strong&gt;express&lt;/strong&gt; refers is the prototype of request objects passed to handler functions; it implements the &lt;code&gt;Request&lt;/code&gt; interface exported by &lt;strong&gt;express-static-serve-core&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The interface &lt;code&gt;Request&lt;/code&gt; imported from &lt;strong&gt;express-static-serve-core&lt;/strong&gt; refers to a Typescript interface and has no runtime meaning&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After we’ve declared the method and added it to the prototype, we can now call it from our route handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get("/foo", async(req, res) =&amp;gt; {
  res.respondWithData({ success: true });
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>node</category>
      <category>express</category>
    </item>
    <item>
      <title>Video.js ❤ Typescript</title>
      <dc:creator>Joe Flateau</dc:creator>
      <pubDate>Fri, 01 Nov 2019 03:45:30 +0000</pubDate>
      <link>https://dev.to/joeflateau/video-js-typescript-3idk</link>
      <guid>https://dev.to/joeflateau/video-js-typescript-3idk</guid>
      <description>&lt;p&gt;I’ve used video.js for about 4 years now, with a brief break where I used a proprietary third party video player. I also love using Typescript. I find the safety the type system provides to be extremely helpful once a web app gets past a certain level of complexity or when time to refactor comes.&lt;/p&gt;

&lt;p&gt;Video.js has a great plugin ecosystem, unfortunately, the plugin model was not super compatible with Typescript. It requires casting the &lt;code&gt;videojs.Player&lt;/code&gt; object to &lt;code&gt;any&lt;/code&gt; which, if you know Typescript, you know means you lose the type checking Typescript provides.&lt;/p&gt;

&lt;p&gt;I decided to do something about it, and started by making some changes to the &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/video.js"&gt;open source typings of video.js in the DefinitelyTyped repository&lt;/a&gt;. The biggest change was exporting a few key interfaces in a way that would allow &lt;a href="https://www.typescriptlang.org/docs/handbook/declaration-merging.html"&gt;module augmentation&lt;/a&gt;. Now your video.js plugins can extend the core video.js interfaces giving type-safe use of these plugins.&lt;/p&gt;

&lt;h3&gt;
  
  
  First things first…
&lt;/h3&gt;

&lt;p&gt;All of the code found in this post is available in &lt;a href="https://stackblitz.com/edit/typescript-videojs-plugin"&gt;this StackBlitz&lt;/a&gt; for you to fork and try things out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Video.js in your Typescript Project
&lt;/h3&gt;

&lt;p&gt;Let’s start with the basics. Let’s create an html video element, install video.js (along with the types from DefinitelyTyped) and initialize a video.js player object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.html&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;video id="video" class="video-js" width="500" height="320" controls&amp;gt;
  &amp;lt;source src="https://vjs.zencdn.net/v/oceans.mp4" type="video/mp4"&amp;gt;&amp;lt;/source&amp;gt;
  &amp;lt;source src="https://vjs.zencdn.net/v/oceans.webm" type="video/webm"&amp;gt;&amp;lt;/source&amp;gt;
  &amp;lt;source src="https://vjs.zencdn.net/v/oceans.ogv" type="video/ogg"&amp;gt;&amp;lt;/source&amp;gt;
&amp;lt;/video&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Install dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm i video.js @types/video.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;index.ts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import videojs from 'video.js';
const player = videojs('video', {})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding Typescript support for someone else’s Video.js plugin
&lt;/h3&gt;

&lt;p&gt;Now let’s try to use a third party video.js plugin. For this example we’ll use the videojs-seek-buttons plugin.&lt;/p&gt;

&lt;p&gt;Install the plugin…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm i videojs-seek-buttons
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now the plugin can be imported. But you can’t actually use it without casting your video.js player object to &lt;code&gt;any&lt;/code&gt;. The following code will NOT work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.ts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import videojs from 'video.js';
import 'videojs-seek-buttons'; // &amp;lt;-- this imports and registers the plugin
const player = videojs('video', {});
// this next line will not actually work because videojs.Player has no method seekButtons
player.seekButtons({ forward: 15, back: 15 });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We need to tell Typescript that this &lt;code&gt;seekButtons&lt;/code&gt; method exists on the &lt;code&gt;VideoJsPlayer&lt;/code&gt; object. To do so, we create &lt;code&gt;d.ts&lt;/code&gt; file that augments the &lt;code&gt;VideoJsPlayer&lt;/code&gt; interface. We’ll also augment &lt;code&gt;VideoJsPlayerPluginOptions&lt;/code&gt;*. Create a new file &lt;code&gt;videojs-seek-buttons.d.ts&lt;/code&gt; (the file name does not actually matter though, you could name it anything.) The contents will be:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;videojs-seek-buttons.d.ts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { VideoJsPlayer, VideoJsPlayerOptions } from 'video.js';

declare module 'video.js' {
  // this tells the type system that the VideoJsPlayer object has a method seekButtons
  export interface VideoJsPlayer {
    seekButtons(options: VideoJsSeekButtonsOptions): void;
  }
  // this tells the type system that the VideoJsPlayer initializer can have options for plugin seekButtons
  export interface VideoJsPlayerPluginOptions {
    seekButtons?: VideoJsSeekButtonsOptions;
  }
}

export interface VideoJsSeekButtonsOptions {
  forward?: number;
  back?: number;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://stackblitz.com/edit/typescript-videojs-plugin?file=videojs-seek-buttons.d.ts"&gt;View in StackBlitz&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I use the types &lt;code&gt;videojs.Player&lt;/code&gt; and &lt;code&gt;VideoJsPlayer&lt;/code&gt; interchangeably. &lt;code&gt;videojs.Player&lt;/code&gt; is a type alias for &lt;code&gt;VideoJsPlayer&lt;/code&gt; so they both refer to the same interface. But you cannot use module augmentation to modify &lt;code&gt;videojs.Player&lt;/code&gt; directly. You need to augment &lt;code&gt;VideoJsPlayer&lt;/code&gt; which will modify &lt;code&gt;videojs.Player&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Adding Typescript support to your Video.js plugin
&lt;/h3&gt;

&lt;p&gt;If you maintained the videojs-seek-buttons project, you would add the type definition found above to your project and reference it in the &lt;code&gt;types&lt;/code&gt; property of your package.json .&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;package.json&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "videojs-seek-buttons",
  "version": "0.0.0",
  "dependencies": {
    ...
  },
  "types": "types/index.d.ts" // &amp;lt;---- wherever you saved that file in your plugin project
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Submitting to DefinitelyTyped
&lt;/h3&gt;

&lt;p&gt;If the maintainer of the plugin does not package the type definition with the project, you can submit them to be included in DefinitelyTyped. See the &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped#create-a-new-package"&gt;DefinitelyTyped Contribution Guide: Create a new package&lt;/a&gt; for instructions on how.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing a Video.js plugin in Typescript
&lt;/h3&gt;

&lt;p&gt;So that was pretty cool, now we can use a plugin authored in Javascript (or coffeescript) in Typescript. What if we now wanted to author a plugin in Typescript?&lt;/p&gt;

&lt;p&gt;It’s not too different to author the plugin in Typescript. You still need to augment the video.js module. Just add that to the end of your main plugin file.&lt;/p&gt;

&lt;p&gt;This plugin will render a button in the player controlBar with a text label and clicking it will trigger an alert box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;example-plugin.ts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import videojs, { VideoJsPlayer } from 'video.js';

const Button = videojs.getComponent('button');

// implement our Button
export class VideoJsExampleButton extends Button {
  static defaultOptions: VideoJsExamplePluginOptions = {
    label: "Default Label",
    message: "Default Message"
  };

  private exampleOptions: VideoJsExamplePluginOptions;

  constructor(
    player: VideoJsPlayer, 
    exampleOptions: Partial&amp;lt;VideoJsExamplePluginOptions&amp;gt; = {}
  ) {
    super(player);

    this.exampleOptions = { 
      ...VideoJsExampleButton.defaultOptions, 
      ...exampleOptions
    };

    this.el().innerHTML = this.exampleOptions.label;
  }

  createEl(tag = 'button', props = {}, attributes = {}) {
    let el = super.createEl(tag, props, attributes);
    return el;
  }

  handleClick() {
    alert(this.exampleOptions.message);
  }
}

videojs.registerComponent('exampleButton', VideoJsExampleButton);

const Plugin = videojs.getPlugin('plugin');

// implement the plugin that adds the button the the controlBar
export class VideoJsExamplePlugin extends Plugin {
  constructor(player: VideoJsPlayer, options?: VideoJsExamplePluginOptions) {
    super(player);
    player.ready(() =&amp;gt; {
      player.controlBar.addChild('exampleButton', options);
    });
  }
}

videojs.registerPlugin('examplePlugin', VideoJsExamplePlugin);

declare module 'video.js' {
  // tell the type system our plugin method exists...
  export interface VideoJsPlayer {
    examplePlugin: (options?: Partial&amp;lt;VideoJsExamplePluginOptions&amp;gt;) =&amp;gt; VideoJsExamplePlugin;
  }
  // tell the type system our plugin options exist...
  export interface VideoJsPlayerPluginOptions {
    examplePlugin?: Partial&amp;lt;VideoJsExamplePluginOptions&amp;gt;;
  }
}

export interface VideoJsExamplePluginOptions {
  label: string;
  message: string;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://stackblitz.com/edit/typescript-videojs-plugin?file=example-plugin.ts"&gt;View in StackBlitz&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion/Footnote
&lt;/h3&gt;

&lt;p&gt;Now you can use your new plugin authored in Typescript. You can either pass the plugin options in the player options object on creation or call the plugin method after initialization.&lt;/p&gt;

&lt;p&gt;index.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import videojs from 'video.js';
import "./example-plugin.ts";
import "videojs-seek-buttons";

const player = videojs('video', {
  plugins: {
    examplePlugin: { message: "Here's a message!" },
    seekButtons: {
      forward: 30,
      back: 10
    }
  }
})

const player2 = videojs('video2', {})

player2.examplePlugin({ 
  label: "Custom button label", 
  message: "Here's a message from player 2!"
});

player2.seekButtons({
  forward: 30,
  back: 10
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It’s my hope that this guide will spur on the adoption of Typescript within the video.js community and the use of video.js within the Typescript community.&lt;/p&gt;

&lt;p&gt;* as of Fri. Oct. 18, 2019 the change to export &lt;code&gt;VideoJsPlayerPluginOptions&lt;/code&gt; has not been merged into @types/video.js quite yet. So you will not see type safety in your video.js setup plugin options yet.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>videojs</category>
    </item>
  </channel>
</rss>
