Implicit Conversions

Functions that convert one type of value to another are quite common.

For example, imagine a situation where you have two Position types from different libraries and you want to create a set of functions to convert from one type to another, and back.

While this might sound like a trivial task, giving these functions an appropriate name is usually an excercise in redundancy:

import * as lsp from "vscode-languageserver-types"
import * as vscode from "vscode"
// this is one possible naming style

function lspPositionToVSCodePosition(p: lsp.Position): vscode.Position {
  /*...*/
}

// or maybe like this?

namespace lspPosition {
  export function toVSCodePosition(p: lsp.Position): vscode.Position {}
}

And naming it is only a small part of the problem:

Introducing x9.convert

The x9.convert function provides a cleaner alternative. (note: x9.convert is one of a series of type-driven extensions to TypeScript - it relies in the compiler to “inject” code at runtime based on type information. this is a controversial feature)

// the following defines a "conversion" function from one type to another

x9.conversion<lsp.Position, vscode.Position>(
  (p) => new vscode.Position(p.line, p.column)
)

// and later, anywhere in your projectconst lspPosition: lsp.Position = {};

// you can simply call x9.convert and pass in the desired type

// the compiler will search for a conversion matching the pair of types (input and output)

// and inject logic if found, or show a compilation error otherwise

const vscodePosition = x9.convert<vscode.Position>(p)

You can also use the @x9.conversion JSDoc annotation

Implicitly applying x9.convert

You can optionally turn on implicit conversions. This will eliminate the need for calling x9.convert altogether.

const p1 = new vscode.Position(0, 0)

// the following typechecks :)
const p2: lsp.Position = p1
const p2 = p1 as lsp.Position

printPosition(p1)

function printPosition(p: lsp.Position) {}