# TypeScript Support

If you're using TypeScript — *as you most definitely should be* — you're in luck! The router is written with first-class support for TypeScript.

That being said, it isn't immediately obvious how to take advantage of type-safety if you use middleware and plugins that extend the context.

Let's say you want to have some middleware that sets a `data` property on the context, like so...

```javascript
import { Router } from '@profiscience/knockout-contrib'

Router.use(async (ctx) => {
  ctx.data = await fetchSomeData()
})
```

Because `ctx` is strongly-typed, we get an error as expected...

> Property 'data' does not exist on type 'Context & IContext'

We could use the dirty `(ctx as any).data = ...` hack that anyone who has used TypeScript for more than a day has undoubtedly had to use, but it would be way better if we could let the compiler know about the new property so we get all the benefits type-safety brings to the table like autocompletion. To do this, it's as simple as adding a `declare` statement to our middleware file, like so...

```typescript
import { Router } from '@profiscience/knockout-contrib'

declare module '@profiscience/knockout-contrib-router' {
  interface IContext {
    data?: MyDataType
  }
}

Router.use(async (ctx) => {
  ctx.data = await fetchSomeData()
})
```

That's it! If `fetchSomeData()` returns something of the wrong type, the compiler will throw an error, and in your component viewModels, you will have full autocomplete of your custom properties.

**NOTE:** It's an interface prefixed with `I`, _not_ the normal `Context` class. This is because TypeScript does not support declaration merging on classes.

You may also take advantage of some types that are exported, namely `RouteConfig`, `RouteMap`, `Middleware`, and `RoutePlugin`. You can use these to specify types where the compiler cannot otherwise infer them. For example...

```typescript
import { Plugin } from '@profiscience/knockout-contrib'

declare module '@profiscience/knockout-contrib-router' {
  interface IContext {
    data: string
  }
  interface IRouteConfig {
    apiUrl: string
  }
}

const apiPlugin: Plugin = ({ apiUrl }) => async (ctx) => {
  ctx.data = await $.get(apiUrl)
}

export default apiPlugin
```

Note, we also augment `IRouteConfig` so that we can get type-safety with the route constructor, i.e.

```typescript
import { Route } from '@profiscience/knockout-contrib'

new Route('/', {
  // this is type-safe!
  apiUrl: 'https://example.com',
})
```
