尝试调用自定义过滤器导致'错误TS2349:无法调用其类型缺少调用签名的表达式'

时间:2015-10-10 21:49:27

标签: angularjs typescript angularjs-filter

我试图从Angular控制器调用自定义过滤器,但是我收到错误: '无法调用类型缺少调用签名的表达式。

我在上一个项目中就这样实现了它,所以我不知道出了什么问题。

此时过滤器不包含任何逻辑,因为我需要先进行编译。

以下是过滤器:

cur = db.cursor()
# Pull records from the database, process each one, and store back into the database
SQLQuery = """SELECT * FROM cybersecurity4.hackhoundposts"""
cur.execute(SQLQuery)
for row in cur:
    postID = row[0]
    threadID = row[1]
    authorID = row[2]
    url = row[3]
    subforum = row[4]
    threadTitle = row[5]
    authorName = row[6]
    postDateTime = row[7]
    postSequence = row[8]
    flatcontent = row[9]
    userTitle = row[11]
    hasAttachment = row[12]

    print (postID)

# #process the flatcontent
    flatcontent = rmvSpecialCharsandCamelCase(flatcontent)

# insert into the database
    try:
        string = """INSERT INTO cybersecurity4.cleanedhackhoundposts
                 (postid, threadid, authorid, URL, subforum, threadTitle, authorName, postdatetime, postSequence, flatcontent, usertitle, hasattachment)
                VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s','%s', '%s', '%s', '%s');""" %  \
             (postID ,threadID,authorID,url,subforum,threadTitle,authorName,postDateTime,postSequence,flatcontent,userTitle,hasAttachment)
        print (string)
        cur.execute(string)
        print ("Successfully inserted post " + str(postID))
    except:
        int("Failed to insert post" + str(postID))

控制器所在的位置:

/// <reference path="../../typings/reference.ts" />

module app {
'use strict';

/**
 * Filter models
 */
export class ModelFilter {
    public static Factory() {
        return function(input: string) {
            console.log(input);
            return input;
        }
    }
}

angular.module('app')
    .filter('modelFilter', [ModelFilter.Factory]);
}

reference.ts:

/// <reference path="../../typings/reference.ts" />

module app {
'use strict';

interface ISearchController {
    vehicles: IVehicles;
    models: any;
    setVehicles(): void;
    updateModels(make: string): void;
}

class SearchController implements ISearchController {

    static $inject = [
        'VehicleMakeService',
        'VehicleModelService',
        '$filter'
    ];
    constructor(private vehicleMakeService: VehicleMakeService,
                private vehicleModelService: VehicleModelService,
                private $filter: ng.IFilterService,
                public vehicles: IVehicles,
                public models: any) {

        this.setVehicles();
    }

    setVehicles(): void {
        this.vehicleMakeService.getVehicles().then((data) => {
            this.vehicles = data;
        });
    }

    updateModels(make: string): void {

        var test = this.$filter('modelFilter')(make); // Error here
    }
}
angular.module('app').controller('SearchController', SearchController);
}

tsd.d.ts:

/// <reference path="./tsd.d.ts" />

//grunt-start
/// <reference path="../app/app.config.ts" />
/// <reference path="../app/app.module.ts" />
/// <reference path="../app/app.route.ts" />
/// <reference path="../app/home/home.controller.ts" />
/// <reference path="../app/home/home.route.ts" />
/// <reference path="../app/models/vehicles.model.ts" />
/// <reference path="../app/results/results.controller.ts" />
/// <reference path="../app/results/results.route.ts" />
/// <reference path="../app/services/cars.service.ts" />
/// <reference path="../app/services/vehicles.make.service.ts" />
/// <reference path="../app/services/vehicles.models.service.ts" />
/// <reference path="../app/templates/search.controller.ts" />
/// <reference path="../app/templates/search.filter.ts" />
//grunt-end

3 个答案:

答案 0 :(得分:10)

修改后的工作示例:

/// <reference path="typings/angularjs/angular.d.ts" />

module app {

    // ADDED <--- MODIFIED!
    export interface MyModelFilter extends ng.IFilterService {
        (name: 'modelFilter'): (input: string) => string;
    }

    /**
     * Filter models
     */
    export class ModelFilter {
        public static Factory() {
            return function(input: string) {
                console.log(input);
                return input;
            }
        }
    }

    angular.module('app')
        .filter('modelFilter', [ModelFilter.Factory]);
}

module app {

    class SearchController {
        constructor(private $filter: MyModelFilter) { // <--- MODIFIED!
        }

        updateModels(make: string): void {
            var test = this.$filter('modelFilter')(make);
        }
    }
    angular.module('app').controller('SearchController', SearchController);
}

问题是TypeScript使用以下definition

/**
 * $filter - $filterProvider - service in module ng
 *
 * Filters are used for formatting data displayed to the user.
 *
 * see https://docs.angularjs.org/api/ng/service/$filter
 */
interface IFilterService {
    (name: 'filter'): IFilterFilter;
    (name: 'currency'): IFilterCurrency;
    (name: 'number'): IFilterNumber;
    (name: 'date'): IFilterDate;
    (name: 'json'): IFilterJson;
    (name: 'lowercase'): IFilterLowercase;
    (name: 'uppercase'): IFilterUppercase;
    (name: 'limitTo'): IFilterLimitTo;
    (name: 'orderBy'): IFilterOrderBy;
    /**
     * Usage:
     * $filter(name);
     *
     * @param name Name of the filter function to retrieve
     */
    <T>(name: string): T;
}

代表this.$filter('modelFilter')。这意味着使用了最后一条规则(即<T>(name: string): T;)。因此,this.$filter('modelFilter')的类型为ng.IFilterService,而TypeScript对您的ModelFilter一无所知。

您可以通过添加新界面来解决问题,如第一个代码清单所示。

你说原始代码在你的另一个项目中起作用,但除非reference.ts以某种方式被修改,否则我似乎不太可能。

答案 1 :(得分:2)

如果您看到IFilterService的最后一行,则自定义过滤器有一个通用类型。

interface IFilterService {
    (name: 'filter'): IFilterFilter;
    (name: 'currency'): IFilterCurrency;
    (name: 'number'): IFilterNumber;
    (name: 'date'): IFilterDate;
    (name: 'json'): IFilterJson;
    (name: 'lowercase'): IFilterLowercase;
    (name: 'uppercase'): IFilterUppercase;
    (name: 'limitTo'): IFilterLimitTo;
    (name: 'orderBy'): IFilterOrderBy;
    /**
     * Usage:
     * $filter(name);
     *
     * @param name Name of the filter function to retrieve
     */
    <T>(name: string): T; 
}

如错误所示,您的自定义过滤器没有调用签名。因此,您可以为过滤器创建一个包含呼叫签名的界面:

export interface MyModelFilter {
    (input: string): string;
}

然后当您调用过滤器时,您可以使用IFilterService的通用类型将您的呼叫签名归因于自定义过滤器

updateModels(make: string): void {
     var test = this.$filter<MyModelFilter>('modelFilter')(make);
}

答案 2 :(得分:0)

我只想分享一个类似的例子,使用Moment库来格式化控制器或前端的日期。

export interface IMomentFilter extends ng.IFilterService {
    (name: 'momentFilter'): (dateString: string, format: string) => string;
}

export class MomentFilter {
    public static Factory() {
        return function (dateString: string, format: string) {
            return moment(dateString).format(format);
        }
    }
}

这是在控制器中使用ag-grid cellRenderer格式化日期的方法:

var columnDefs = [
{
    headerName: "Reported Date", 
    field: "reportedDate", 
    cellRenderer: function (params) 
    {
        return $filter('momentFilter')(params.value, "MM/DD/YYYY");
    }
}];

这是如何在前端使用的:

<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">Created Date:
    <label class="field">
    <label class="field">{{vm.model.reportedDate| momentFilter:'MM/DD/YYYY' }}</label>
    </label>
</div>

我希望这会有所帮助。非常感谢原帖。我真的很想弄清楚使用IFilterService接口获得正确的语法。