TypeScript z KnockoutJS

137

Czy jest jakiś przykład użycia TypeScript z KnockoutJS? Jestem po prostu ciekawy, jak by razem pracowali?

Edytować

Oto, co mam, wydaje się działać

declare var ko: any;
declare var $: any;
class ViewModel {
    x = ko.observable(10);
    y = ko.observable(10);

}

$(() => {
    ko.applyBindings(new ViewModel());
});

Generuje się to w następującym JavaScript:

var ViewModel = (function () {
    function ViewModel() {
        this.x = ko.observable(10);
        this.y = ko.observable(10);
    }
    return ViewModel;
})();
$(function () {
    ko.applyBindings(new ViewModel());
});
CallumVass
źródło
6
Byłem nieco zdezorientowany słowem kluczowym "deklaruj" używanym w połączeniu z "var", dopóki nie znalazłem w specyfikacji sekcji o deklaracjach otoczenia. Teraz ma to sens: typescriptlang.org/Content/… .
Rex Miller
2
W maszynopisie mamy Generics 0,9, co daje wpisałeś obserwable: ko.observable<number>(10). Napisałem post na blogu z bardziej szczegółowymi informacjami: ideasof.andersaberg.com/idea/12/…
Anders

Odpowiedzi:

108

Spójrz na DefinitelyTyped .

„Repozytorium definicji typów TypeScript dla popularnych bibliotek JavaScript”

George Mavritsakis
źródło
3
To może być głupie pytanie, ale czy możesz wyjaśnić, czym dokładnie jest definicja typu TypeScript? Czy jest to wyłącznie po to, aby można było używać funkcji bibliotecznych w pliku skompilowanym przez TypeScript bez narzekania kompilatora? W takim przypadku nie musiałbyś odwoływać się do definicji w swojej aplikacji, tylko podczas kompilowania plików ts, prawda?
niezaprzeczalnie
9
Tak właśnie jest. Gdybyś pisał swój kod maszynowy w notatniku, potrzebowałbyś tylko definicji w czasie kompilacji. Z drugiej strony, jedną z zalet maszynopisu jest to, że studio wizualne (i innym edytorom dzięki wtyczkom) jest łatwiejsze do zrozumienia twojego kodu i pomaga ci w automatycznym uzupełnianiu i sprawdzaniu typów i błędów (znacznie więcej niż JavaScript). Dlatego używamy plików definicji dla kodu napisanego w JavaScript, aby zapewnić kontrolę typu maszynopisu. Oczywiście możesz zadeklarować biblioteki jako „dowolne”, ale to nie jest dobre. Mam nadzieję, że pomogłem!
George Mavritsakis
5
Zwróć uwagę, że kluczem jest dodanie /// <reference path="knockout-2.2.d.ts" />na początku pliku .ts, aby pobierał definicje.
Aidan Ryan
Nie widzę nokautu nigdzie na liście… usunięto ?? przeniósł?? sfrustrowany
Jester
58

Zrobiłem ten mały interfejs, aby uzyskać statyczne typy dla Knockout:

interface ObservableNumber {
        (newValue: number): void;               
        (): number;                             
        subscribe: (callback: (newValue: number) => void) => void;
}
interface ObservableString {
        (newValue: string): void;               
        (): string;                             
        subscribe: (callback: (newValue: string) => void) => void;
}
interface ObservableBool {
    (newValue: bool): void;             
    (): bool;                               
    subscribe: (callback: (newValue: bool) => void) => void;
}

interface ObservableAny {
    (newValue: any): void;              
    (): any;                                
    subscribe: (callback: (newValue: any) => void) => void;
}

interface ObservableStringArray {
    (newValue: string[]): void;
    (): string[];
    remove: (value: String) => void;
    removeAll: () => void;
    push: (value: string) => void;
    indexOf: (value: string) => number;
}

interface ObservableAnyArray {
    (newValue: any[]): void;
    (): any[];
    remove: (value: any) => void;
    removeAll: () => void;
    push: (value: any) => void;
}

interface Computed {
    (): any;
}

interface Knockout {
    observable: {
        (value: number): ObservableNumber;
        (value: string): ObservableString;
        (value: bool): ObservableBool;
        (value: any): ObservableAny;
    };
    observableArray: {
        (value: string[]): ObservableStringArray;
        (value: any[]): ObservableAnyArray;
    };
    computed: {
        (func: () => any): Computed;
    };
}

Umieść go w „Knockout.d.ts”, a następnie odwołaj do niego z własnych plików. Jak widać, bardzo skorzystałby na generycznych (które są dostarczane zgodnie ze specyfikacjami).

Zrobiłem tylko kilka interfejsów dla ko.observable (), ale ko.computed () i ko.observableArray () można łatwo dodać w tym samym wzorcu. Aktualizacja: Poprawiłem podpisy dla subscribe () i dodałem przykłady computed () i obserableArray ().

Aby użyć z własnego pliku, dodaj to u góry:

/// <reference path="./Knockout.d.ts" />
declare var ko: Knockout;
Sten L.
źródło
2
@JcFx: Anders wspomniał prawdopodobnie o możliwości pobrania pliku TypeScript .ts i wyprowadzenia pliku deklaracji interfejsu .d.ts. Nie ma sposobu, aby wziąć zwykły, nietypowy JavaScript i magicznie odkryć typy. Problem z JS (który TypeScripts próbuje rozwiązać) polega na tym, że programista nie ma możliwości zadeklarowania swojego zamiaru, aby zmienna była zgodna z określonym typem. Kiedy mówisz x = 'hello'w JS, nie wiemy, czy gdzieś później w swoim kodzie zamierzałeś to powiedzieć x = 34. Nie możemy jednak niczego wywnioskować o typie x.
Sten L
@JcFx: właściwie możesz mieć rację, że niektóre ograniczone informacje mogą pochodzić ze zwykłego JS. Daj mi znać, kiedy spróbujesz!
Sten L
maszynopis dodaje generics.
Daniel A. White
6

Nic nie zmieniłoby się pod względem sposobu deklarowania powiązań typu knockout w znacznikach, jednak otrzymalibyśmy inteligencję po napisaniu interfejsów dla biblioteki knockout. Pod tym względem działałby tak jak przykład jQuery , który ma plik maszynopisu zawierający interfejsy dla większości api jQuery .

Myślę, że jeśli pozbędziesz się dwóch deklaracji zmiennych dla ko i $, twój kod zadziała. Ukrywają one rzeczywiste zmienne ko i $, które zostały utworzone podczas ładowania skryptów knockout i jquery.

Musiałem to zrobić, aby przenieść projekt szablonu programu Visual Studio na nokaut:

app.ts:

class GreeterViewModel {
    timerToken: number;
    utcTime: any;

    constructor (ko: any) { 
        this.utcTime = ko.observable(new Date().toUTCString());
        this.start();
    }

    start() {
        this.timerToken = setInterval(() => this.utcTime(new Date().toUTCString()), 500);
    }
}

window.onload = () => {
    // get a ref to the ko global
    var w: any;
    w = window;
    var myKO: any;
    myKO = w.ko;

    var el = document.getElementById('content');
    myKO.applyBindings(new GreeterViewModel(myKO), el);
};

default.htm:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>TypeScript HTML App</title>
    <link rel="stylesheet" href="app.css" type="text/css" />
    <script src="Scripts/knockout-2.1.0.debug.js" type="text/javascript"></script>
    <script src="app.js"></script>
</head>
<body>
    <h1>TypeScript HTML App</h1>

    <div id="content" data-bind="text: utcTime" />
</body>
</html>
Jeremy Danyow
źródło
1
Czy wysyłanie w ko do każdego konstruktora to przesada
Simon_Weaver
3

Ok, więc po prostu użyj następującego polecenia, aby zaimportować typy wybicia lub tds.

npm install @types/knockout

Spowoduje to utworzenie katalogu @types w katalogu projektów node_modules, a plik definicji typu wycięcia indeksu będzie znajdować się w katalogu o nazwie knockout. Następnie poprzez odwołanie z potrójnym ukośnikiem do pliku types. Zapewni to świetne funkcje IDE i TypeScript.

/// <reference path="../node_modules/@types/knockout/index.d.ts" />

Na koniec użyj po prostu deklaracji, aby przenieść zmienną ko do zakresu. To jest mocno wpisane na maszynie, więc cześć, inteligencja.

declare var ko: KnockoutStatic;

Więc teraz możesz używać KO tak jak w swoich plikach javascript.

wprowadź opis obrazu tutaj

Mam nadzieję że to pomoże.

SimperT
źródło