2017-10-18 2 views
0

Je veux une classe qui se comporte comme la fonction Date js:tapuscrit: interface fonctionnelle avec le constructeur

  1. un appel par new il crée une instance de la classe.
  2. lorsqu'il est appelé en tant que fonction, il fait des choses statiques.

Comment implémenter cette interface?

interface A { 
    (): string; 
    new(arg: number); 
    GetValue(): number; 
} 

solution actuelle qui ne compile pas mais produit code correct dans la cour:

class B implements A { 

    private Value: number; 

    constructor(arg: number) { 
     if (this.constructor == B) { 
      this.Value = arg; 
     } else { 
      return "42"; 
     } 
    } 

    GetValue(): number { 
     return this.Value; 
    } 
} 

Répondre

1

Vous ne pouvez pas utiliser un ES2015 ou laterclass pour vous faire appeler un constructeur sans le mot-clé new. À l'étape 2 de la section 9.2.1 des documents liés, l'appel d'un constructeur de classe sans le mot-clé new doit entraîner le lancement d'un TypeError. (Si vous ciblez ES5 dans TypeScript, vous obtiendrez quelque chose qui fonctionne à l'exécution, mais si vous ciblez ES2015 ou au-dessus, vous obtiendrez des erreurs d'exécution.) Il est préférable de ne pas le faire. -ES2015 fonction constructeur à la place. Par ailleurs, la signature new(arg: number) nécessite un type de retour. Par exemple:

interface A { 
(): string; 
    new(arg: number): AInstance; // return something 
    GetValue(): number; 
} 
// define the instance type 
interface AInstance { 
    instanceMethod(): void; 
} 

est ici une façon de mettre en oeuvre. Tout d'abord, faire une class pour AInstance:

class _A implements AInstance { 
    constructor(arg: number) { } // implement 
    instanceMethod() { } // implement 
} 

Ensuite, une fonction qui peut être appelée avec ou sans new:

const AFunctionLike = 
    function(arg?: number): AInstance | string { 
    if (typeof arg !== "undefined") { 
     return new _A(arg); 
    } 
    return "string"; 
    } as { new(arg: number): AInstance,(): string }; 

J'ai décidé que si vous appelez AFunctionLike avec un argument vous obtiendra un AInstance, sinon vous obtiendrez un string. Vous pouvez également vérifier explicitement si new a été utilisé, via new.target, si votre runtime est compatible.

Notez également que je devais affirmer que AFunctionLike est newable (avec la clause as sur la dernière ligne) car il n'y a actuellement aucun autre moyen de dire tapuscrit qu'une fonction autonome peut être appelée avec new.

Maintenant nous avons presque terminé. Nous pouvons déclarer une valeur de type A comme suit:

const A: A = Object.assign(
    AFunctionLike, 
    { 
    GetValue() { 
     return 1; 
    } 
    } 
); 

La valeur A a été formée par la fusion AFunctionLike avec un objet qui implémente GetValue(). Vous pouvez utiliser Object.assign ou spread syntax pour effectuer cette fusion.


C'est tout. Vous pouvez vérifier que cela fonctionne à l'exécution on the TypeScript Playground. Bonne chance!