TypeScript dynamic loading of AMD module ends in "Could not find symbol '...' - visual-studio

No, this topic won't answer my question and NO, the solution is not simply importing Command in the nav.ts file. nav.ts is one of many viewModel-files and they will be loaded dynamically on demand. The only problem is to set the parameter's type in the constructor of the class. (Type has to be "Command")
In the following class, which will be loaded by require.js, the method viewModel() requires a new class dynamically. In this case NavViewModel .
command.ts
export class Command {
...
public viewModel(name: string, callback: Function) {
require(["noext!boot/getViewModel/" + name], function (viewModel) {
callback(viewModel);
});
}
}
This is the class which will be fetched by viewModel():
nav.ts
export class NavViewModel extends kendo.Router {
constructor(command: Command) {
super();
this.route('/:name', function (name) {
command.view(name, $('div.content'));
});
this.start();
}
}
EDIT:
Here is the entry-point (requested in comment 2)
main.ts (EntryPoint)
import lib = require("command");
var cmd = new lib.Command();
cmd.viewModel('nav', function (o) {
cmd.view('nav', $('div.header'), function () {
kendo.bind($('.header .nav'), new o.NavViewModel(cmd));
});
});
/EDIT
The Problem:
Visual Studio will throw the error TS2095: Could not find symbol 'Command', because the "Command" class ist not defined in this Module.
The program works fine if the "Command"-Type will be removed from the NavViewModel constructor. Is there any solution to reference the Command class in the NavViewModel?
This won't work:
/// <reference path="../../Scripts/command.ts" />

When using RequireJS, the import statement should be the full path from the root of the application.
I also use a slightly different export syntax
command.ts
class command {
...
}
export = command;
main.ts
// I'm assuming the Scripts folder is at the root of the application
import Command = require('Scripts/command');
var cmd = new Command();
Note
I'm using Typescript 0.9.1.1. I can't upgrade my machine to 0.9.5 as a large internal application is affected by some breaking changes between versions

Related

How to use someClass.android.ts and someClass.ios.ts without errors

I'm using nativescript angular. I have a class called SomeClass that access the native API of iOS and Android separately.
I've written two files:
someclass.android.ts
export class SomeClass {
someFunction() {
if(isAndroid) {
// do some android specific code
}
}
}
someclass.ios.ts
export class SomeClass {
someFunction() {
if(isIOS) {
// do some ios specific code
}
}
}
Now, in app.component.ts, I'm using SomeClass like this:
import { SomeClass } from './../shared-code/someclass';
without .android.ts or .ios.ts, to enable nativescript to pick the right file depending on the running platform.
and then in the code, I user SomeFunction like this:
...
const someClass = new SomeClass();
someClass.someFunction();
...
With this setting, everything works perfectly on both iOS and Android, but I get the following error
error TS2307: Cannot find module './../shared-code/someclass'.
Do you have any idea how to tell nativescript/tslint to take into account the .android and .ios files and not to display this error?
Thanks
Here's the solution:
Alongside 'someclass.ios.ts' and 'someclass.android.ts', create a definitions file and name it 'someclass.d.ts' (Not index.d.ts). No need to put the files in a separate folder.
In someclass.d.ts, export declare the class like this:
export declare class SomeClass {
/**
* someFunction, is a function that does this and that (description)
*/
someFunction(): void;
}
Then, you can use this from another file like this:
In app.component.ts:
import { SomeClass } from './../shared-code/someclass';
Remember to use /someclass without any extensions.
This would solve build and tslint errors.

Aurelia: Calling functions from the Chrome debug console

I am experienced, but new to Aurelia and cannot figure out how to call a specific function from the console.
Using this source:
<code>
import {} from 'css/style.css';
import {inject} from 'aurelia-framework';
import {DOM} from 'aurelia-pal';
export class App {
constructor() {
this.message = 'Test Application';
this.todos = ['a','b','c','d'];
this.DOM = DOM;
}
getFish() {
this.DOM.getElementById("#theMessage").style.color="green";
}
}
</code>
I want to call getFish from the console. One may think that App.getFish() would do it, but no so much.
How DOES one call class functions in the debug console for Aurelia?
I would simply log this in the constructor or really in any of the VM's functions:
export class App {
constructor() {
console.log('App VM', this);
}
getFish() {
console.log('get fish called');
}
}
Then I would right click on the the object that is logged and click "Store as global variable." That will give me a variable to use. I can then call the function as desired.

Jasmine Unit testing define library that was imported as a global variable

I have a project that uses pdfMake to generate a PDF. To use it I include the file in my index.html
<script src='js/pdfmake.js'></script>
<script src='js/vfs_fonts.js'></script>
Inside pdfmake.js it declares global["pdfMake"] which then allows me to use the library in my service.
pdfService:
pdfMake.createPdf(docDefinition).download(fileName);
Everything works great but when I tried to test ths method in my service I get an error that the test can't find the variable pdfMake. That makes sense considering it's loaded by index.html.
How can I replace this library with a mock in my test?
I've tried using a spy but since makePdf isn't a function that doesn't work. spyOn(service, 'makePdf').
I tried just setting it as a variable but that also didn't work and I get: Strict mode forbids implicit creation of global property 'pdfMake'
pdfMake = {
createPdf: jasmine.createSpy('createPdf').and.returnValue({
download: jasmine.createSpy('download')
}
}
I got the same problem and solved inserting the pdfMake mock on global variable window inside the unit test. So, in your case will be something like this:
window.pdfMake = {
createPdf: jasmine.createSpy('createPdf')
.and.returnValue({
download: jasmine.createSpy('download')
}),
};
I just fixed this issue by making below changes-
Declare pdfMake variable globally in your .ts file like-
declare var pdfMake;
And then mock the pdfMake function in your .spec file like this-
window['pdfMake'] = {
createPdf: function (param) {
return {
open: function () {
return true;
},
download: function () {
return true;
}
};
}
};

How do I reference a Typescript enum inside a definition file

I am using Visual Studio 2013 with update 4 and Typescript 1.3 installed.
If I have a typescript file, like so:
MyEnums.ts:
export = MyEnumModule;
module MyEnumModule {
export enum AnEnum { RED, BLUE, GREEN }
}
And I have a definitions file like so:
MyDefinitions.d.ts:
declare module MyDefinitions {
interface ISomeInterface {
aProperty: string;
aMethod: () => void;
aColor: MyEnumModule.AnEnum;
}
}
I basically get an error of "Cannot find name 'MyEnumModule'"
This enum file works fine when referenced from typescript files. For instance:
SomeCode.ts:
export = MyCode;
import MyEnums = require('MyEnums');
module MyCode{
export class MyClass implements ISomeInterface {
public aColor: MyEnums.AnEnum = MyEnums.AnEnum.RED;
...and so on
My understanding is that adding either /// <reference ... or an import will not work for a .d.ts file (I tried just to be sure and it didn't appear to work either way).
Does anyone know how to reference an enum in a definition file like this?
Thanks in advance.
--Update:
Here is the error I see after trying Steve Fenton recommendations below (with a sample project I just made).
MyDefinitions.ts:
import MyEnumModule = require('../App/MyEnums');
declare module MyDefinitions {
interface ISomeInterface {
aProperty: string;
aMethod: () => void;
aColor: MyEnumModule.AnEnum;
}
}
MyEnums.ts:
export = MyEnumModule;
module MyEnumModule {
export enum AnEnum { RED, BLUE, GREEN }
}
MyClass.ts:
export = MyCode;
import MyImport = require('MyEnums');
module MyCode {
export class MyClass implements MyDefinitions.ISomeInterface {
public aColor: MyImport.AnEnum = MyImport.AnEnum.RED;
constructor() { }
aProperty: string = "";
aMethod: () => void = null;
}
}
Folder structure:
App
-MyClass.ts
-MyEnums.ts
Defintions
-MyDefintions.d.ts
Inside MyClass.ts MyDefinitions.ISomeInterface is underlined in red with hover warning "Cannot find name MyDefinitions".
I have AMD set for the project
Does anyone know how to reference an enum in a definition file like this?
There are workaround as Steve Fenton pointed out, but the system isn't designed for this. You should reference other definition files in your definition file and not reference an *implementation file * (MyEnum.ts) in a definition file.
I had a check on this and the following definition works for me, although I must admit I have never referenced "actual" code from "definition" code - but I can't think of any reason not to.
import MyEnumModule = require('MyEnumModule');
declare module MyDefinitions {
interface ISomeInterface {
aProperty: string;
aMethod: () => void;
aColor: MyEnumModule.AnEnum;
}
}
On mixing definitions and real implementations...
The type system in TypeScript is a design time and compile-time tool. When the type information is constructed at design time it makes no difference whether the type information is inferred from implementation code, taken from annotations that decorate implementations or come from an ambient declaration.
There are many use cases for mixing implementation code and ambient declarations - if you are migrating a million-line JavaScript program to TypeScript, you may not be able to migrate it from the bottom-most dependency upwards. Also, you can place ambient declarations inside of normal files - not just definition files - if you have a large program, you may not even know whether a type you place in an ambient declaration is "real" or "ambient".
The only difference between implementation code types and ambient declaration types is that the type information is right next to the implementation in real code files, and in a separate file for ambient declarations.
So... if you are having a problem using real implemented types in your ambient declaration, it is most likely caused by something that can be fixed. The example I supplied above works in a project I have in Visual Studio 2013, Update 4 - with TypeScript build configuration set to compile AMD modules. If you can share the exact details of the problem, I'm happy to help you get it working.
Having said this - if you are creating a type definition for trivial amounts of code, pasting them into a .ts file may even be faster than writing the definition - so you should make a case-by-case decision on where to spend the effort.

Selenium RC User Defined Functions

Trying to do something simple -
I have a set of statements to clear browser cookies:
public void clearCookies () {
selenium.open("http://www.myurl.com");
selenium.waitForPageToLoad("10000");
selenium.deleteAllVisibleCookies();
}
Now, if I use this function in a test script (using TestNG), calls to this work perfectly. However, if I moved this function to a separate class and change the declaration to include "static", the "selenium" keyword is not recognized.
In a configuration class (say configClass),
public static void clearCookies () {
selenium.open("http://www.myurl.com");
selenium.waitForPageToLoad("30000");
selenium.deleteAllVisibleCookies();
}
Now, in my test script, if I call configClass.clearCookies();, I get a runtime error
I tried declaring DefaultSelenium selenium = new DefaultSelenium(null);, in the clearCookies() function, but that too results in a runtime error.
I do have the import com.thoughtworks.selenium.*; import in my configClass.
Any pointers would be appreciated. Thanks.
You can do two things.
Refer to the same selenium object in both the classes i.e. in configClass and the class you are calling configClass.clearCookies().
or else
send selenium object to the clearCookies. So the code would be like this
public static void clearCookies (DefaultSelenium selenium) {
selenium.open("http://www.myurl.com");
selenium.waitForPageToLoad("30000");
selenium.deleteAllVisibleCookies();
}

Resources