AngularJS@1.4.5中TypeScript移植指令无法获取控制器引用问题
我之前也遇到过类似的移植问题,结合你的描述和纯JS版本的正常表现,大概率是TypeScript环境下指令定义的细节没和原JS版本对齐,导致ngModel控制器没被正确注入。下面是你需要排查和修正的几个关键点:
1. 检查指令的require配置是否正确
这是最常见的出错点:你必须确保TypeScript版的指令定义里,明确设置了require: 'ngModel',和纯JS版本完全一致。如果漏掉这个配置,AngularJS根本不会尝试注入ngModel控制器,自然会出现undefined的错误。
正确的指令定义示例(工厂函数方式):
angular.module('yourApp') .directive('unitConverter', (): ng.IDirective => { return { restrict: 'A', // 和原JS保持一致,原JS是属性指令 require: 'ngModel', // 必须明确声明依赖ngModel link: (scope: ng.IScope, elem: JQuery, attrs: ng.IAttributes, ngModel: ng.INgModelController) => { // 先做防御性检查,避免后续报错 if (!ngModel) { console.error("unitConverter指令必须搭配ngModel使用"); return; } // 接下来就可以正常使用ngModel.$parsers、$formatters了 ngModel.$parsers.push((value) => { // 你的输入转换逻辑,和原JS一致 }); ngModel.$formatters.push((value) => { // 你的输出转换逻辑,和原JS一致 }); } }; });
2. 确认link函数的参数顺序绝对正确
AngularJS指令的link函数参数顺序是固定的:scope → element → attributes → 依赖的控制器。如果你的TS代码里把ngModel放在了第三个参数的位置,或者漏写了参数,就会导致拿到的不是ngModel实例。
错误示例(参数顺序错误):
// ❌ 错误:把ngModel放在了第三个参数的位置 link: (scope: ng.IScope, elem: JQuery, ngModel: ng.INgModelController) => { // 这里的ngModel其实是attrs对象,自然没有$parsers属性 }
3. 类式指令的特殊注意事项
如果你用了装饰器(比如angular-decorators)来写类式指令,记得要添加@Require('ngModel')装饰器,同时在构造函数中正确注入NgModelController:
import { Directive, Require, NgModelController, ElementRef, Attributes, Scope } from 'angular-decorators'; @Directive({ selector: '[unitConverter]', restrict: 'A' }) @Require('ngModel') // 必须添加这个装饰器声明依赖 export class UnitConverterDirective { constructor( @Scope() private scope: ng.IScope, @ElementRef() private elem: JQuery, @Attributes() private attrs: ng.IAttributes, private ngModel: NgModelController // 依赖注入ngModel控制器 ) { this.init(); } private init(): void { if (!this.ngModel) return; // 在这里编写转换逻辑 } }
4. 确保scope配置和原JS一致
如果原JS指令中有自定义scope(比如scope: { unit: '@' }),一定要在TS版本中完全复现。不一致的scope配置可能会干扰指令的初始化流程,间接导致ngModel注入失败。
最后补充:引入AngularJS类型定义
确保你已经安装了@types/angular依赖,这样TypeScript才能正确识别ng.INgModelController、ng.IScope等类型,避免隐性的类型错误影响代码执行。
内容的提问来源于stack exchange,提问作者Snæbjörn

