140

Is there any sample of using TypeScript with KnockoutJS? I'm just curious as to how they would work together?

Edit

Here is what I have, seems to work

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

}

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

This generates into the following Javascript:

var ViewModel = (function () {
    function ViewModel() {
        this.x = ko.observable(10);
        this.y = ko.observable(10);
    }
    return ViewModel;
})();
$(function () {
    ko.applyBindings(new ViewModel());
});
CallumVass
  • 11,288
  • 26
  • 84
  • 154
  • 6
    I was somewhat confused by the "declare" keyword used in conjunction with "var" until I found the section on Ambient Declarations in the spec. Makes perfect sense now: http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf. – Rex Miller Oct 02 '12 at 21:01
  • 2
    In Typescript 0.9 we have Generics, which gives you typed observables: `ko.observable(10)`. I wrote a blogpost with some more detailed information: http://ideasof.andersaberg.com/idea/12/typescript-09-generics-what-and-how-to-use-them – Anders Jun 26 '13 at 08:20

6 Answers6

109

Look at DefinitelyTyped.

"TypeScript type definitions repository for popular JavaScript libraries"

George Mavritsakis
  • 6,829
  • 2
  • 35
  • 42
  • 3
    This may be a dumb question, but can you explain what exactly a TypeScript type definition is/does? Is it purely so that you can use library functions in a TypeScript-compiled file without the compiler complaining? If that's the case, you wouldn't need to reference the definition in your application, just when you compile the ts files, correct? – undeniablyrob Nov 29 '12 at 21:39
  • 9
    That is exactly the case. If you were writing your typescript code in notepad, you would only need the definitions at compile time. On the other hand, one of the good points of typescript is that it is easier for the visual studio (and other editors through plugins) intellisence to understand your code and it helps you much with auto completion and perform type and error checking (much more than JavaScript). That is why we use definition files for code written in JavaScript so as to provide typescript type checking. Of course you could declare libs as "any", but this is not good.hope I helped! – George Mavritsakis Dec 01 '12 at 16:03
  • 5
    Note that the key is to add `/// ` to the top of your .ts file so that it picks up the definitions. – Aidan Ryan Dec 07 '12 at 23:59
  • I don't see knockout anywhere in the list....removed?? moved?? frustrated – Jester Sep 06 '19 at 13:38
58

I made this little interface to get static types for 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;
    };
}

Put it in "Knockout.d.ts" and then reference it from your own files. As you can see, it would benefit greatly from generics (which are coming according to the specs).

I only made a few interfaces for ko.observable(), but ko.computed() and ko.observableArray() can be easily added in the same pattern. Update: I fixed the signatures for subscribe() and added examples of computed() and observableArray().

To use from your own file, add this at the top:

/// <reference path="./Knockout.d.ts" />
declare var ko: Knockout;
Sten L
  • 1,772
  • 1
  • 12
  • 13
  • 2
    @JcFx: What Anders referred to was probably the option to take a TypeScript .ts file and output an interface declaration file .d.ts. There is no way to take regular untyped JavaScript and magically discover the types. The problem with JS (that TypeScripts tries to solve) is that there is no way for the programmer to declare her intention that a variable should conform to a particular type. When you say `x = 'hello'` in JS, we don't know if you intended somewhere later in your code to say `x = 34`. Hance we can infer nothing about the type of x. – Sten L Oct 06 '12 at 12:57
  • @JcFx: actually, you may be right that some limited type information could be derived from plain JS. Let me know how it goes when you try! – Sten L Oct 08 '12 at 13:34
  • typescript is adding generics. – Daniel A. White Oct 08 '12 at 16:54
14

Try my realisation of TypeScript interface declarations (with simple example)
https://github.com/sv01a/TypeScript-Knockoutjs

Florent
  • 12,310
  • 10
  • 49
  • 58
Sv01a
  • 149
  • 3
6

Nothing would change in terms of the way knockout bindings are declared in the markup however we would get the intellisense goodness once the interfaces are written for the knockout library. In this respect it would work just like the jquery Sample, which has a typescript file containing interfaces for most of the jQuery api.

I think if you get rid of the two variable declarations for ko and $ your code will work. These are hiding the actual ko and $ variables that were created when the knockout and jquery scripts loaded.

I had to do this to port the visual studio template project to knockout:

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
  • 26,470
  • 12
  • 87
  • 133
5

Ok so just use the following command to import the knockout types or tds.

npm install @types/knockout

This will create a @types directory in your projects node_modules directory and the index knockout type definition file will be in a directory named knockout. Next, through a triple-slash reference to the types file. This will give great IDE and TypeScript features.

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

Finally, just use a declare statement to bring the ko variable into scope. This is strongly-typed so hello intellisense.

declare var ko: KnockoutStatic;

So now you can use KO just like in your javascript files.

enter image description here

Hope this helps.

SimperT
  • 2,837
  • 2
  • 15
  • 19
  • 1
    This was perfect for me in 2021. Mixing Typescript in with old existing Javascript while leveraging npm. Thank you. – Hallmanac Feb 03 '21 at 16:14
2

I am using https://www.nuget.org/packages/knockout.editables.TypeScript.DefinitelyTyped/ and it has all interfaces for Knockout.

JavaScript Linq
  • 2,605
  • 3
  • 13
  • 12