bcherny
bcherny

Reputation: 3172

How do I add typings for an existing Angular1 $filter function in TypeScript?

My filter (JavaScript):

angular.module('foo').filter('bar', function() {
  return function(a, b, c) {
    return a + b + c
  }
})

My consumer (TypeScript):

$filter('bar')('a', 'b', 'c') // Error: Cannot invoke an expression whose type lacks a call signature

Here is the typing for $filter

How can I add typings for my filter? I've tried the following, which doesn't seem to work:

interface BarFilter {
  (a: string, b: string, c: string): string
}

module angular {
  interface IFilterService {
    (name: 'bar'): BarFilter // Error: Specialized overload signature is not assignable to any non-specialized signature
  }
}

Upvotes: 0

Views: 303

Answers (2)

Andreas Jägle
Andreas Jägle

Reputation: 12260

Like @basarat mentioned, you can specify this on every invocation on $filter to determine the type you expect to get back, e.g. as a specific version like this:

$filter<BarFilter>("bar")("x", "y", "z")

... which is not much better than using a type cast.

Another option is to extend the ng.IFilterService interface and add all the filters you registered there. Then when injecting the $filter, just specify YourIFilterService insted of ng.IFilterService:

interface YourIFilterService extends ng.IFilterService {
    (name: "bar"): BarFilter
}

And using it like this:

class BarController {
    constructor(private $filter: YourIFilterService) {}

    doBarFiltering() {
        var bars = this.$filter("bar")("x", "y", "z")
    }
}

In my opinion, this is a good way to achieve a pretty good level of type safety with not that much more effort, as you would add typings to $filter anyways (as ng.IFilterService).

Upvotes: 2

basarat
basarat

Reputation: 275957

You need to the provide the type explicitly (notice that T isn't determined by any of the inputs to the declaration of $filter). A quick one:

$filter<Function>('bar')('a', 'b', 'c')

Upvotes: 0

Related Questions