gadeynebram gadeynebram - 1 month ago 15
TypeScript Question

Is it possible to assign all module imports as a return type?

I'm new to Typescript (1.8). I'm transforming a project that was written for angular 1.4 to typescript.

One of the things I did was create a D3Service that loads the d3.js library asynchronously and makes it available in a promise.

This is my tranformed code to typescript:

namespace D3Provider{

export class D3Service{
static $inject = ['$document', '$window', '$q', '$rootScope','$timeout'];

public d3: ng.IPromise<{}>;

constructor(
private $document: ng.IDocumentService,
private $window: ng.IWindowService,
private $q: ng.IQService,
private $rootScope: ng.IScope,
private $timeout: ng.ITimeoutService){
var d = $q.defer();
this.d3=d.promise;
function onScriptLoad() {
// Load client in the browser
$timeout(function(){
$rootScope.$apply(function () {
d.resolve($window['d3']);
});
});
}
var scriptTag = $window.document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.async = true;
scriptTag.charset="utf-8"
scriptTag.src = 'bower_components/d3/d3.min.js';
scriptTag.onload = onScriptLoad;

var s = $document[0].getElementsByTagName('body')[0];
s.appendChild(scriptTag);
}
}
angular.module('d3', [])
.service('d3Service', D3Service);
}


The public d3 property holds a promise that contains the values from window.d3.

I've downloaded the typings file which is available in ../../typings/modules/d3/index.d.ts

In the code I've then tried things like:

/// <reference path="../../typings/modules/d3/index.d.ts" />

import * as d3lib from 'd3';
...
public d3: ng.IPromise<d3lib>;


The compiler then complains: error TS2304: Cannot find name 'd3lib'.

Answer

Alternatively, you could make your promise void (call it ready or something like that) and when it is resolved - you can access d3 as global variable/namespace.

public ready: ng.IPromise<void>;

...

var d = $q.defer();
this.ready = d.promise;
var scriptTag = $window.document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.async = true;
scriptTag.charset="utf-8"
scriptTag.src = 'bower_components/d3/d3.min.js';
scriptTag.onload = () => d.resolve();
var s = $document[0].getElementsByTagName('body')[0];
s.appendChild(scriptTag);

Then you can use it:

d3Service.ready.then(() => {
   //d3 can be used here 
});

Also, no need in $timeout and $scope.$apply

Comments