2017-04-16 43 views
2

的类型,为了给这个问题有点背景的,我有一个要求,其母公司提供的回调子组件。 这是AngularJS的典型场景。
由于我使用的打字稿,我想在子组件强类型的回调。使用类或接口的方法

这里的初始状态,没有任何强烈的分型:

class ParentComponentController { 
    public parentMethod(param1: number, param2: string): boolean { 
    return param1 > 0 && param2.length > 2; 
    } 
} 

class ChildComponentController { 
    constructor(private parentMethod: Function) {} 

    public onCertainTrigger() { 
    this.parentMethod(10, 'something'); 
    } 
} 

这是我怎么能实现强大的打字,但它似乎很凌乱:

declare type parentMethod = (param1: number, param2: string) => boolean; 

interface ICommonApi { 
    parentMethod: parentMethod; 
} 

class ParentComponentController implements ICommonApi { 
    public parentMethod(param1: number, param2: string): boolean { 
    return param1 > 0 && param2.length > 2; 
    } 
} 

class ChildComponentController { 
    constructor(private parentMethod: parentMethod) { } 

    public onCertainTrigger() { 
    this.parentMethod(10, 'something'); 
    } 
} 

理想情况下,我想象这是一-衬垫。是这样的可能吗?

class ParentComponentController { 
    public parentMethod(param1: number, param2: string): boolean { 
    return param1 > 0 && param2.length > 2; 
    } 
} 

class ChildComponentController { 
    // This results in an error 
    constructor(private parentMethod: ParentComponentController.parentMethod) {} 

    public onCertainTrigger() { 
    this.parentMethod(10, 'something'); 
    } 
} 
+0

正如答案中所解释的那样,第二个片段对于TS来说是惯用的,并且已经具有最不合理的代码量,而单行可能有启发性,但肯定不实际。在这里寻找一线球员基本上是代码高尔夫(顺便说一下,这是SO的offtopic)。 – estus

+0

@estus你的回答对于TS来说可能是惯用的,但在JS中传递回调是很常见的。我想要一个强有力的键入回调的简短方法,而不必创建其他类型和接口;一条线就能实现这一点。在我看来,这不是“代码高尔夫”,因为我正在寻找TS的特定功能。 –

+0

这是如何在TS中完成的。如果您需要键入的内容,这是一种类型,应该明确定义。做你想做的事情是一个黑客,除了它更短(这是代码高尔夫的定义),没有任何好处。如果它只是一次只使用一次,那么你应该在每个地方明确指定回调类型,'(n:number,s:string)=> boolean',我已经用解释更新了答案。其语义是,它不是'控制器方法类型',而是'恰好是与控制器方法类型相同的某种类型'。 – estus

回答

2

这。

class ParentComponentController { 
    public parentMethod(param1: number, param2: string): boolean { 
    return param1 > 0 && param2.length > 2; 
    } 
} 

class ChildComponentController { 
    constructor(private parentMethod: typeof ParentComponentController.prototype.parentMethod) {} 

    public onCertainTrigger() { 
    this.parentMethod(10, 'something'); 
    } 
} 
+0

这似乎是一个非常有力的竞争者。你能否提供一些官方文档的链接来解释'typeof'在TypeScript中的工作原理? –

+1

请参阅https://basarat.gitbooks.io/typescript/docs/types/moving-types.html。虽然这不是官方的,但@basarat的这个文档非常有名和可靠。我找不到关于'typeof'的好官方文档。 – kimamula

2

还没一个内胆,但东西,可以节省你明确地维护父类的方法类型:

declare let parentController: ParentComponentController; 

class ChildComponentController { 
    constructor(private parentMethod: typeof parentController.parentMethod) {} 
} 
+0

我真的很喜欢这种方法!正如你所说,这不是一条线,而是非常接近它(只有2条线)。 –

1

正如你已经宣布typeparentMethod,你也可以做类似如下:

declare type parentMethod = (param1: number, param2: string) => boolean; 

class ParentComponentController { 

    //this is now a field of type parentMethod 
    public parentMethod: parentMethod = (param1: number, param2: string) => 
    param1 > 0 && param2.length > 2; 
} 

class ChildComponentController { 
    constructor(private parentMethod: parentMethod) { } 

    public onCertainTrigger() { 
    this.parentMethod(10, 'something'); 
    } 
} 

new ChildComponentController(new ParentComponentController().parentMethod) 
    .onCertainTrigger(); 

这里是小提琴链接,您referecne:https://jsfiddle.net/sayan751/ttmzzkg9/

0

您可以创建一个命名空间这还不是特别大的类型别名,但将努力:

class ParentComponentController { 
    public parentMethod(param1: number, param2: string): boolean { 
    return param1 > 0 && param2.length > 2; 
    } 
} 
namespace ParentComponentController { 
     export type parentMethod = (number, string) => boolean; 
} 

class ChildComponentController { 
    // This results in an error 
    constructor(private parentMethod: ParentComponentController.parentMethod) {} 

    public onCertainTrigger() { 
    this.parentMethod(10, 'something'); 
    } 
} 

注意接口,以及类型别名,不要在运行时存在。他们只是一个设计时间构造。

0

Generics and Generic Constraints的主要目的是描述类型的关系。

interface ICommonApi { 
    parentMethod(param1: number, param2: string): boolean; 
} 

class ParentComponentController { 
    public parentMethod(param1: number, param2: string): boolean { 
     return param1 > 0 && param2.length > 2; 
    } 
} 

class ChildComponentController<P extends ICommonApi> { 
    constructor(private parent:P) { } 

    public onCertainTrigger() { 
     this.parent.parentMethod(10, 'something'); 
    } 
} 

let p = new ParentComponentController(); 
let c = new ChildComponentController(p); 

如果界面很简单:

class ParentComponentController { 
    public parentMethod(param1: number, param2: string): boolean { 
     return param1 > 0 && param2.length > 2; 
    } 
} 

class ChildComponentController<P extends { parentMethod: (param1: number, param2: string) => boolean}> { 
    constructor(private parent:P) { } 

    public onCertainTrigger() { 
     this.parent.parentMethod(10, 'something'); 
    } 
} 

let p = new ParentComponentController(); 
let c = new ChildComponentController(p); 
0

在原岗位的“乱”片段是这样做的正确方法。这是TypeScript最佳实践的建议。事实是,parentMethod是一种类型,并与一些命名空间包裹它像ParentComponentController.parentMethod没有做什么都好。

它落入相同的情况下,在Needless Namespacing section手动地址:

重申为什么你不应该尝试命名空间的模块内容,命名空间的总体思路是,以提供结构的逻辑分组和防止名称冲突。因为模块文件本身已经是一个逻辑分组,并且其顶级名称由导入它的代码定义,所以不必为导出的对象使用额外的模块层。

尽管是在词的广义的命名空间,预计命名空间中键入像ParentComponentController.parentMethod类型属于相同的原理,奥卡姆剃刀之内。名称空间类型提供了不必要的复杂性,但对设计没有任何优势。

代码可以使用T-除了I之前的自定义类型的前缀匈牙利符号 - 前缀接口。对于其他OO语言来说,这是常规的,特别是C#(TypeScript严重借鉴)。还应该注意到,well-known Coding guidelines document是指在TypeScript代码中使用前缀,并且不禁止在其他地方使用匈牙利符号。

所以基本上最好的方式保持不变,可能使用TParentMethod而不是晦涩parentMethod类型的可读性:

declare type TParentMethod = (param1: number, param2: string) => boolean; 

interface ICommonApi { 
    parentMethod: TParentMethod; 
} 

class ParentComponentController implements ICommonApi { 
    public parentMethod(param1: number, param2: string): boolean { ... } 
} 

class ChildComponentController { 
    constructor(private parentMethod: TParentMethod) { } 
    ... 
} 

如果只发生一次的回调函数类型或两次,不需要单独的类型应该明确指定功能签名:

class ChildComponentController { 
    constructor(private parentMethod: (n: number, s: string) => boolean) { } 
    ... 
} 

这提供了保持代码类型安全的必要级别的冗余。