126 votes

Construire un objet fonction avec des propriétés en TypeScript

Je veux créer un objet fonction, qui possède également certaines propriétés. Par exemple, en JavaScript, je le ferais :

var f = function() { }
f.someValue = 3;

Maintenant, en TypeScript, je peux décrire le type de ceci comme :

var f: { (): any; someValue: number; };

Cependant, je ne peux pas le construire, sans avoir besoin d'un casting. Par exemple :

var f: { (): any; someValue: number; } =
    <{ (): any; someValue: number; }>(
        function() { }
    );
f.someValue = 3;

Comment construiriez-vous ceci sans moule ?

120voto

Greg Weber Points 918

Mise à jour : Cette réponse était la meilleure solution dans les versions antérieures de TypeScript, mais il existe de meilleures options dans les versions plus récentes (voir les autres réponses).

La réponse acceptée fonctionne et peut s'avérer nécessaire dans certaines situations, mais elle présente l'inconvénient de ne fournir aucun type de sécurité pour la construction de l'objet. Cette technique déclenchera au moins une erreur de type si vous tentez d'ajouter une propriété indéfinie.

interface F { (): any; someValue: number; }

var f = <F>function () { }
f.someValue = 3

// type error
f.notDeclard = 3

113voto

Meirion Hughes Points 1855

Ceci est facilement réalisable maintenant (typescript 2.x) avec Object.assign(target, source)

exemple :

enter image description here

La magie ici est que Object.assign<T, U>(t: T, u: U) est tapé pour retourner le intersection T & U .

Il est également simple de s'assurer que la résolution renvoie à une interface connue. Par exemple :

interface Foo {
  (a: number, b: string): string[];
  foo: string;
}

let method: Foo = Object.assign(
  (a: number, b: string) => { return a * a; },
  { foo: 10 }
); 

qui se trompe en raison d'une incompatibilité de typage :

Erreur : foo:number not assignable to foo:string
Erreur : nombre non assignable à string[] (type de retour)

_avertissement : vous devrez peut-être polyfill Object.assign si vous visez des navigateurs plus anciens._

61voto

mk. Points 620

TypeScript est conçu pour gérer ce cas par le biais de fusion de déclarations :

vous connaissez peut-être aussi la pratique du JavaScript qui consiste à créer une fonction, puis à étendre cette fonction en y ajoutant des propriétés. TypeScript utilise la fusion de déclarations pour construire des définitions de ce type d'une manière sûre.

La fusion des déclarations nous permet de dire que quelque chose est à la fois une fonction et un espace de nom (module interne) :

function f() { }
namespace f {
    export var someValue = 3;
}

Cela préserve la typographie et nous permet d'écrire à la fois f() y f.someValue . Lors de la rédaction d'un .d.ts pour le code JavaScript existant, utilisez declare :

declare function f(): void;
declare namespace f {
    export var someValue: number;
}

L'ajout de propriétés aux fonctions est souvent un motif de confusion ou d'inattendu dans TypeScript, donc essayez de l'éviter, mais cela peut être nécessaire lors de l'utilisation ou de la conversion de code JS plus ancien. C'est l'une des seules fois où il serait approprié de mélanger des modules internes (espaces de noms) avec des modules externes.

33voto

nxn Points 957

Donc, si l'exigence est de construire simplement et d'assigner cette fonction à "f" sans un casting, voici une solution possible :

var f: { (): any; someValue: number; };

f = (() => {
    var _f : any = function () { };
    _f.someValue = 3;
    return _f;
})();

Essentiellement, elle utilise une fonction littérale auto-exécutoire pour "construire" un objet qui correspondra à cette signature avant que l'affectation ne soit effectuée. La seule bizarrerie est que la déclaration interne de la fonction doit être de type 'any', sinon le compilateur s'écrie que l'on assigne à une propriété qui n'existe pas encore sur l'objet.

EDIT : J'ai simplifié un peu le code.

11voto

George Platko Points 76

Vieille question, mais pour les versions de TypeScript à partir de la version 3.1, vous pouvez simplement effectuer l'affectation des propriétés comme vous le feriez en JS ordinaire, à condition d'utiliser une déclaration de fonction ou la fonction const pour votre variable :

function f () {}
f.someValue = 3; // fine
const g = function () {};
g.someValue = 3; // also fine
var h = function () {};
h.someValue = 3; // Error: "Property 'someValue' does not exist on type '() => void'"

Référence y [exemple en ligne](https://www.typescriptlang.org/play/index.html#src=function%20f%20()%20%7B%7D%0D%0Af.someValue%20%3D%203%3B%0D%0Aconst%20g%20%3D%20function%20()%20%7B%7D%3B%0D%0Ag.someValue%20%3D%203%3B%0D%0Avar%20h%20%3D%20function%20()%20%7B%7D%3B%0D%0Ah.someValue%20%3D%203%3B%0D%0A) .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X