Construiește un obiect funcție cu proprietăți dactilografiat

voturi
46

Vreau să creeze un obiect functie, care are, de asemenea, unele proprietăți deținute pe ea. De exemplu, în JavaScript I-ar face:

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

Acum dactilografiat pot descrie tipul de acest lucru ca:

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

Cu toate acestea nu se poate construi de fapt, fără a necesita o distributie. Precum:

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

Cum ai construi acest lucru fără o distributie?

Întrebat 07/10/2012 la 07:08
sursa de către utilizator
În alte limbi...                            


9 răspunsuri

voturi
73

Actualizare: Acest răspuns a fost cea mai bună soluție în versiunile anterioare dactilografiate, dar există opțiuni mai bune disponibile în versiuni mai noi (a se vedea alte răspunsuri).

Răspunsul acceptat funcționează și ar putea fi necesare în anumite situații, dar au dezavantajul de a oferi nici o siguranță de tip pentru construirea obiectului. Aceasta tehnica va arunca cel puțin o eroare de tip dacă încercați să adăugați o proprietate nedefinită.

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

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

// type error
f.notDeclard = 3
Publicat 05/09/2013 la 16:12
sursa de către utilizator

voturi
34

Typescript este proiectat să se ocupe de acest caz , prin declarație contopire :

ar putea fi, de asemenea, familiarizat cu practica JavaScript de a crea o funcție și apoi se extinde funcția prin adăugarea de proprietăți pe funcția. Typescript folosește declarația fuzionare pentru a construi definiții ca acest lucru într-un mod de tip în condiții de siguranță.

Declarația fuzionare ne permite să spunem că ceva este în același timp o funcție și un spațiu de nume (modul intern):

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

Acest lucru păstrează dactilografiere și ne permite să scrie atât f()și f.someValue. Când scrieți un .d.tsfișier de cod JavaScript existent, utilizați declare:

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

Adăugarea de proprietăți la funcții este de multe ori un model confuz sau neașteptate dactilografiat, așa că încercați să-l evite, dar poate fi necesară atunci când se utilizează sau o conversie mai vechi cod de JS. Aceasta este una dintre singurele momente în care ar fi oportun să se amestece module interne () cu spații de nume externe.

Publicat 28/10/2015 la 13:47
sursa de către utilizator

voturi
27

Acest lucru este ușor de realizat acum (dactilografiat 2.x), cu Object.assign(target, source)

exemplu:

introduceți descrierea imaginii aici

Magia aici este că Object.assign<T, U>(...)este tastat să returneze o intersecție tip de T & U.

Aplicarea că aceasta rezolvă într-o interfață de cunoscut este, de asemenea, drept înainte:

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

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

Eroare: foo: număr nu repartizabile foo: string
Eroare: număr nu repartizabile string [] (tip de retur)

caveat: poate fi necesar să polyfill Object.assign dacă țintirea browsere mai vechi.

Publicat 25/01/2017 la 13:43
sursa de către utilizator

voturi
17

Deci, dacă cerința este de a construi pur și simplu și să atribuie această funcție de „f“ fără o distributie, aici este o soluție posibilă:

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

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

În esență, se folosește o funcție de executare auto literală a „construi“ un obiect care se va potrivi cu semnătura înainte de atribuirea se face. Singura ciudatenie este faptul că declarația interioară a funcției trebuie să fie de tip „orice“, în caz contrar compilatorul plânge că sunteți atribuirea la o proprietate care nu exista pe obiect încă.

EDIT: simplificată codul un pic.

Publicat 07/10/2012 la 17:33
sursa de către utilizator

voturi
1

Nu pot spune că este foarte simplu, dar este posibil, cu siguranta:

interface Optional {
  <T>(value?: T): OptionalMonad<T>;
  empty(): OptionalMonad<any>;
}

const Optional = (<T>(value?: T) => OptionalCreator(value)) as Optional;
Optional.empty = () => OptionalCreator();

dacă ai curios acest lucru este de la GIST de- al meu cu versiunea typescript / JavaScript deOptional

Publicat 07/02/2018 la 23:57
sursa de către utilizator

voturi
1

Un răspuns actualizat: întrucât adăugarea de tipuri de intersecție , prin intermediul &, este posibil să se „fuzioneze“ două tipuri deduse pe zbor.

Iată un ajutor general , care citește proprietățile unui obiect fromși să le copii de peste un obiect onto. Ea se întoarce același obiect , ontodar cu un nou tip , care include ambele seturi de proprietăți, care descrie în mod corect comportamentul de rulare:

function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
    Object.keys(from).forEach(key => onto[key] = from[key]);
    return onto as T1 & T2;
}

Acest ajutor de nivel scăzut încă nu efectuează o afirmație de tip, dar este de tip sigur prin design. Cu acest ajutor, în loc, avem un operator pe care o putem folosi pentru a rezolva problema PO cu siguranță de tip complet:

interface Foo {
    (message: string): void;
    bar(count: number): void;
}

const foo: Foo = merge(
    (message: string) => console.log(`message is ${message}`), {
        bar(count: number) {
            console.log(`bar was passed ${count}`)
        }
    }
);

Click aici pentru a încerca în typescript Playground . Rețineți că am constrânsă foosă fie de tip Foo, astfel încât rezultatul mergetrebuie să fie completă Foo. Deci , dacă redenumiți barbadatunci veți obține o eroare de tip.

NB Există încă o gaură tip aici, cu toate acestea. Typescript nu oferă o modalitate de a constrânge un parametru de tip să fie „nu este o funcție“. Deci , ai putea obține confuz și să treacă funcția ta ca al doilea argument merge, și că nu ar funcționa. Deci , până când acest lucru poate fi declarată, trebuie să - l prindem în timpul rulării:

function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
    if (typeof from !== "object" || from instanceof Array) {
        throw new Error("merge: 'from' must be an ordinary object");
    }
    Object.keys(from).forEach(key => onto[key] = from[key]);
    return onto as T1 & T2;
}
Publicat 10/03/2016 la 19:14
sursa de către utilizator

voturi
1

Ca o comandă rapidă, puteți atribui în mod dinamic valoarea obiectului folosind [ „proprietate“] accessor:

var f = function() { }
f['someValue'] = 3;

Aceasta ocolește verificarea de tip. Cu toate acestea, este destul de sigur că aveți pentru a avea acces în mod intenționat proprietatea în același mod:

var val = f.someValue; // This won't work
var val = f['someValue']; // Yeah, I meant to do that

Cu toate acestea, dacă doriți cu adevărat tipul de verificare pentru valoarea proprietății, acest lucru nu va funcționa.

Publicat 11/10/2012 la 05:38
sursa de către utilizator

voturi
0

Vechea întrebare, dar pentru versiunile dactilografiate incepand cu 3.1, puteți face pur și simplu atribuirea proprietății așa cum ați face în simplu JS, atâta timp cât utilizați o declarație funcție sau constcuvântul cheie pentru variabila:

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'"

De referință și de exemplu on - line .

Publicat 26/11/2018 la 21:38
sursa de către utilizator

voturi
0

Acest lucru se îndepărtează de la tastare puternică, dar poți să faci

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

dacă încercarea de a obține tastarea puternic în jurul opresive ca am fost atunci când am găsit această întrebare. Din păcate acest lucru este un caz nu typescript JavaScript perfect validă, astfel că trebuie să-ți spun typescript să renunțe.

„Tu JavaScript este perfect valabil typescript“ evaluează la fals. (Notă: folosind 0,95)

Publicat 21/02/2014 la 16:59
sursa de către utilizator

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more