Git Product home page Git Product logo

angularjs-typescript's Introduction

AngularJS + Typescript ♥♥

Follow Along:

github.com/seanhess/angularjs-typescript

video from ng-conf 2014

About Me

Sean Hess

Code and Startups

WHY TYPESCRIPT?

Story of a Javascript App

  • started fast with JS
  • house of cards
  • testing was hard

Typescript: be happy

  • like waking up on Christmas with well-written, fast tests
  • formalize your choices as you go
  • modern features make it easy: optional, inferred

see mistakes right away, in context

Editor Errors

autocomplete

Editor Autocomplete

WHAT IS TYPESCRIPT?

  • basically compiles ES6 to JavaScript
  • plus a modern type system

Getting Started

Install Typescript

> npm install -g typescript

It is just JavaScript/ES6

function hello(name) {
    alert("hello " + name)
}
hello("world")

Compile It

> tsc test.ts

Add Types to Variables

Try these in the Typescript Playground: www.typescriptlang.org/Playground

var population:number = 3

var name:string = "hello"
var names:string[] = [name];

var user:User;

var couldBeAnything;

Produces output that looks the same

Interfaces

Make some rules and keep them

interface User {
    firstName: string;
    lastName: string;
}

// interface matches any object with the right fields
var user:User = {firstName:"Very", lastName:"User"}
var user2:User = {name:"Very User"} // error

function fullName(user:User):string {
    return user.firstName + " " + user.lastName;
}

Type Inference

The compiler can read your mind

Telepathy

// name is a string
var name = fullName(user)

function sum(a:number, b:number) {
    return a + b
}

var result = sum(name, 4)

Generics

Code for what things have in common

function firstValue<T>(array:T[]):T {
    return array[0]
}

// these will give errors.
var one:string = firstValue([1,2,3,4,5])
var two:number = firstValue(["one", "two"])

ES6 Features

External Modules: can output CommonJS or AMD

// users.ts
export function fullName(user:User):string {
    return user.firstName + " " + user.lastName
}

// main.ts
import users = require("./users")
var name = users.fullName(user)

Internal Modules

module users {
    export function fullName(user:User):string {
        return user.firstName + " " + user.lastName
    }
}

var name = users.fullName(user)

Classes

class Animal {
    public size:number;
    constructor() {
        this.size = 0;
    }
}

class Kitten extends Animal {
    public furriness:number

    devour(animal:Animal) {
        this.size += animal.size
    }

    get isCute() {
        return (this.size < 10 && this.furriness > 5)
    }
}

Fat Arrow Functions

var service = {
    names: [],

    loadNames: function() {
        $.get("/users", (users) => {

            // cheap inline functions
            var firstNames = users.map((user) => user.firstName)

            // "this" still works!
            this.names = firstNames
        })
    }
}

Definition Files

External type definition files for many libraries on DefinitelyTyped

declare module ng {
    interface IScope {
        $parent:IScope;
        $eval(expressions:string):any;
        $watch(expressions:string):any;
        ... 
    }
}

function MyController(scope:ng.IScope) {}

IDE and Editor Integration

Error checking and Autocomplete:

TYPESCRIPT + ANGULAR

Add Typescript to TodoMVC AngularJS

Start with TodoMVC, let's add Typescript to it

http://todomvc.com/architecture-examples/angularjs/

Start with your Data Model

Make a file with shared application types: types.ts. Data first design.

interface Todo {
    completed: boolean;
    title: string;
}

Add :Todo to function signatures

function createTodo(text):Todo {
    return {
        title: text,
        completed: false
    }
}

Add Definition Files

/// <reference path="./types/jquery/jquery.d.ts"/>
/// <reference path="./types/angularjs/angular.d.ts"/>
/// <reference path="./types/angularjs/angular-route.d.ts"/>

interface Todo {
    completed: boolean;
    title: string;
}

Angular Controller

Start with todoCtrl.js

todomvc.controller('TodoCtrl', function TodoCtrl($scope, $routeParams, todoStorage, filterFilter) {
    var todos = $scope.todos = todoStorage.get();
    ...
})

todoCtrl.ts: Add some interfaces for the scope and params

interface TodoCtrlScope extends ng.IScope {
    todos:Todo[];
    newTodo:string;
    editedTodo:Todo;
    originalTodo:Todo;
    remainingCount:number;
    completedCount:number;
    allChecked:boolean;
    status:string;
    statusFilter:{completed:boolean};

    addTodo();
    editTodo(todo:Todo);
    doneEditing(todo:Todo);
    revertEditing(todo:Todo);
    removeTodo(todo:Todo);
    clearCompletedTodos(todo);
    markAll(completed:boolean);
}

interface TodoCtrlRouteParams {
    status:string;
}

Add types to the parameters

todomvc.controller('TodoCtrl', function TodoCtrl($scope:TodoCtrlScope, $routeParams:TodoCtrlRouteParams, todoStorage:TodoStorage, filterFilter) {
    var todos = $scope.todos = todoStorage.get();
    ...
})

To use classes consider the view model method

Angular Service

Start with todoStorage.js

todomvc.factory('todoStorage', function () {
    var STORAGE_ID = 'todos-angularjs';

    return {
        get: function () {
            return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]');
        },

        put: function (todos) {
            localStorage.setItem(STORAGE_ID, JSON.stringify(todos));
        }
    };
});

To make todoStorage.ts, let's use a class

class TodoStorage {
    static STORAGE_ID = 'todos-angularjs';

    // dependencies would be injected here
    constructor() {

    }

    get():Todo[] {
        return JSON.parse(localStorage.getItem(TodoStorage.STORAGE_ID) || '[]');
    }

    put(todos:Todo[]) {
        localStorage.setItem(TodoStorage.STORAGE_ID, JSON.stringify(todos));
    }
}

for classes use .service() instead of .factory()

todomvc.service('todoStorage', TodoStorage)

Lets you formalize an API

Alternatively, you could just add an interface

Add a build step

Add a build step to your Gruntfile.js

grunt.initConfig({
    exec: {
        tsPublic: { cmd: 'node_modules/.bin/tsc public/js/app.ts public/js/**/*.ts -t ES5'},
    },

    watch: {
        public: {
            files: ["public/**/*.ts"],
            tasks: ["exec:tsPublic"],
            options: { livereload: true },
        },
    }
})

grunt.registerTask('default', ['exec:tsPublic', 'watch'])

Then just run grunt, and start saving files

> grunt

No way to type views :(

<!-- should be .title, but no error -->
<label>{{todo.text}}</label>

Using ES6 Modules

  • simplest: just include all the generated .js files
  • add a build script: grunt concat
  • namespaces? use internal modules
  • with browserify or AMD: use external modules

Live Code: Refactoring a Service

  • Let's add promises! What could go wrong?
  • Typescript will save us!

What about Dart? Coffeescript?

  • There can be only one
  • was worth giving up Coffeescript
  • Dart has a cool type system, but it is all-in.

Other cool things you could try:

  • Rich models with classes

IT'S OVER!

github.com/seanhess/angularjs-typescript

Concat Me: @seanhess

TODO: paste in images of IDEs

angularjs-typescript's People

Contributors

neil-rubens avatar seanhess avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angularjs-typescript's Issues

jQuery TS definitions file doesn't include jqLite version of .on()

The jquery.d.ts definition of .on() should include a version without the optional selector parameter since specifying that parameter will result in a jqlite runtime error:

jqLite#on() does not support the `selector` or `eventData` parameters

And TypeScript won't compile a jqLite-compatible version of the .on() method with the current definition:

error TS2345: Argument of type 'string' is not assignable to parameter of type '{ [key: string]: any; }'.

Question about typescript style of implementation.

I have a medium-sized project (~15-20k SLOC). It was coded under a tight deadline so there's hardly any tests. Now the the initial deadline to demo it is passed, we can prep it for production. As a first step, rather than write tests for everything, I think there's a lot to be gained by typscripting it first, then adding tests to the most core features as time allows.

I'm at a loss for what style is the best approach. I'm comparing your project to this one. Specifically, this project template seems to go much farther extremes in using the typescript features to rigidify the app.

As a starting point, looking at their app.js, it is far more rigorous. It has functions to register every controller, service, directive etc. This may seem like overkill, but it allows us to use the module pattern in the controllers, as such:

module app.controllers {
    export class MyController implements IController {
        constructor (private $scope, private myService) {
            $scope.message = myService.someMethod();
        }
    }
}

So What i'm asking is, is santialbo's complexity really necessary? I mean, I like the idea of being very strict everywhere, but on the other hand, I have a lot of js files to convert. I kind of like your hybrid approach where we kind of leave the angulary-parts in vanilla js, but add some type definitions for the $scope and models. I mean, there's not a whole lot to a controller or a directive that really needs type definitions. I'd think it's mainly models and such you want to be sure you can refactor easily.

todomvc.controller('TodoCtrl', function TodoCtrl($scope:TodoCtrlScope, $routeParams:TodoCtrlRouteParams, todoStorage:TodoStorage, filterFilter) {
    var todos = $scope.todos = todoStorage.get();
    ...

I just don't want to shoot my self in the foot and not get the "strictness" I crave. Maybe this is a weird question, but I'm a TS noob. In santialbo's example app.js do I need those module registrations to declare controllers as he does? If I understand correctly, his example app tries to make first-class typescript objects/classes/modules out of the boilerplate angular objects, is this correct?

great intro vid, btw.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.