Vybudovat funkční objekt s vlastnostmi na psacím stroji

hlasů
46

Chci vytvořit objekt funkce, která má i některé vlastnosti držené na něm. Například v JavaScriptu budu dělat:

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

Nyní na stroji mohu popsat typ to jako:

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

Nicméně nemohu vlastně stavět, aniž by bylo nutné obsazení. Jako:

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

Jak byste stavět to bez obsazení?

Položena 07/10/2012 v 07:08
zdroj uživatelem
V jiných jazycích...                            


9 odpovědí

hlasů
73

Aktualizace: Tato odpověď byla nejlepším řešením v dřívějších verzích strojopisu, ale existují lepší možnosti k dispozici v novějších verzích (viz další odpovědi).

Akceptovanou odpověď funguje a může být nutné v některých situacích, ale mají nevýhodu poskytovat žádné bezpečnostní typu pro vybudování objektu. Tato technika bude nejméně hodit chybu typu, pokud se pokusíte přidat nedefinovanou vlastnost.

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

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

// type error
f.notDeclard = 3
Odpovězeno 05/09/2013 v 16:12
zdroj uživatelem

hlasů
34

Strojopis je navržen tak, aby zvládnout tento případ prostřednictvím prohlášení sloučení :

může být rovněž obeznámeni s praxí JavaScript vytvořit funkci a pak rozšiřuje funkci dále přidáním vlastnosti na funkci. Strojopisem používá prohlášení slučování vybudovat definic, jako je to v typově bezpečným způsobem.

Prohlášení sloučení nám umožňuje říci, že něco je jak funkcí a názvů (interní modul):

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

To zachovává psát a nám umožňuje psát i f()i f.someValue. Při psaní .d.tssoubor pro stávající kód JavaScriptu, použijte declare:

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

Přidání vlastnosti funkce je často matoucí nebo neočekávané vzor na stroji, takže se mu vyhnout, ale to může být nezbytné při používání nebo konverzi starší kód JS. To je jeden z mála časů by bylo vhodné kombinovat interní moduly (jmenných prostorů) s externím.

Odpovězeno 28/10/2015 v 13:47
zdroj uživatelem

hlasů
27

To je snadno dosažitelné nyní (strojopis 2.x) s Object.assign(target, source)

příklad:

zadejte popis obrázku zde

Magie je, že Object.assign<T, U>(...)je napsaný vrátit průniku typ T & U.

Vymáhání, že to řeší známého rozhraní je také přímočará:

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

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

Chyba: foo: číslo nelze přiřadit k foo: řetězec
Chyba: číslo, které není převoditelná na řetězec [] (návrat typ)

Upozornění: budete muset polyfill Object.assign pokud cílení starší prohlížeče.

Odpovězeno 25/01/2017 v 13:43
zdroj uživatelem

hlasů
17

Takže v případě, že požadavek je jednoduše vytvořit a tuto funkci na „f“ přiřadit bez obsazení, zde je možné řešení:

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

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

V podstatě používá vykonávající funkci samočinného doslovný na „postavit“ objekt, který bude odpovídat ten podpis před úkol je hotov. Jediným podivnost je, že vnitřní deklarace funkce musí být typu ‚každý‘, jinak překladač pláče, že jste přiřazení k nemovitosti, která neexistuje na objekt dosud.

EDIT: Zjednodušené Kodexu trochu.

Odpovězeno 07/10/2012 v 17:33
zdroj uživatelem

hlasů
1

Nemohu říci, že je to velmi jednoduché, ale je to určitě možné:

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

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

pokud máte zvláštní to je z podstaty mého s verzí strojopisu / JavaScriptuOptional

Odpovězeno 07/02/2018 v 23:57
zdroj uživatelem

hlasů
1

Aktualizovaný odpověď: protože přidáním typů křížení přes &to je možné „sloučit“ dva typy odvozené v reálném čase.

Zde je obecný pomocník, který čte vlastnosti nějakého objektu froma kopie je přes objekt onto. Vrátí stejný objekt onto, ale s novým typem, který obsahuje obě sady vlastností, takže správně popisuje chování za běhu:

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

Tento low-level pomocník má ještě provést typu tvrzení, ale je to typ bezpečné záměrné. S tímto pomocníkem v místě, máme operátor, který můžeme použít k vyřešení problému OP je s plnou bezpečností typu:

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}`)
        }
    }
);

Klikněte sem to vyzkoušet ve strojopisu hřiště . Všimněte si, že jsme omezené foobýt typu Foo, takže výsledek mergemusí být kompletní Foo. Takže pokud jste přejmenování barse badpak dostanete chybu typu.

NB Tam je ještě jeden druh díra, nicméně. Strojopisem neposkytuje způsob, jak omezovat parametr typu, aby byl „není funkce“. Takže byste mohli dostat zmatený a předat svou funkci jako druhý argument merge, a že to nebude fungovat. Takže dokud to může být prohlášena, musíme ho chytit za běhu:

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;
}
Odpovězeno 10/03/2016 v 19:14
zdroj uživatelem

hlasů
1

Jako zástupce můžete dynamicky přidělit hodnotu objektu pomocí [ ‚majetkem‘] přístupový:

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

To obchází kontroly typu. Nicméně, to je docela bezpečné, protože musíte záměrně přístup k vlastnosti stejným způsobem:

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

Nicméně, pokud opravdu chcete typ kontroly pro majetkové hodnoty, to nebude fungovat.

Odpovězeno 11/10/2012 v 05:38
zdroj uživatelem

hlasů
0

Stará otázka, ale pro verze strojopisu počínaje 3.1, můžete jednoduše provést přiřazení vlastností, jako byste v prostém JS, tak dlouho, jak můžete použít deklarace funkce nebo constklíčové slovo pro proměnné:

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

Referenční a on-line příkladem .

Odpovězeno 26/11/2018 v 21:38
zdroj uživatelem

hlasů
0

To se liší od silné psaní, ale můžete to udělat

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

pokud se snažíte dostat kolem tyranské silný psaní, jako jsem byl, když jsem se na tuto otázku našel. Bohužel to je případ, strojopisem selže dokonale platný JavaScript, takže musím říct strojopisem ustoupit.

„Ty JavaScript je dokonale platný strojopisu“ vyhodnocen jako false. (Poznámka: za použití 0,95)

Odpovězeno 21/02/2014 v 16:59
zdroj uživatelem

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