سؤال

please help me with the following problem. I created default node.js app with express using Visual Studio nodejs tools and now I'm trying to call setTimeout function that is declared in node.d.ts. The code is like this:

var timer: NodeTimer;
timer = setTimeout(somecallback, 1000);

But the code doesn't compile saying 'Cannot convert 'Number' to 'NodeTimer''

As I understand, the problem is that it takes standard setTimeout function instead of taking the one from node.d.ts.

I tried specifying the reference to node.d.ts with \\\<reference> tag - this doesn't help. How can I state explicitly that I want to use setTimeout from node.d.ts?

هل كانت مفيدة؟

المحلول

I suspect that this was broken by a change introduced in TS 0.9.5, which is described in the changelog as:

Overload resolution rules simplified

Description: Overload resolution now follows a much simpler algorithm. When multiple overloads fit for a given call, we pick the first fit rather than the trying to find the "best fit".

This means that code with overloads should now be manually sorted from the tightest/more-specific overload to loosest.

The two overloads that are available are the following:

// in lib.d.ts
declare function setTimeout(handler: any, timeout?: any, ...args: any[]): number;

// in node.d.ts
declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeTimer;

Clearly, the first overload will always match everything the second one can match, so it will always be preferred so long as it is the first one considered.

In the case where there are two .d.ts files, as it is here, the order of files defines the relative order of overloads from them. Normally, lib.d.ts always comes first, so it gets the priority. However, if you manually reference it, and make sure that the reference goes after node.d.ts, then the latter will take priority and you will end up with the correct overload.

Doing this from command line is easy - just specify .d.ts files explicitly in the desired order. For a VS project, you can do the same with _references.ts, like so:

/// <reference path="Scripts/typings/node/node.d.ts" />
/// <reference path="C:\Program Files (x86)\Microsoft SDKs\TypeScript\1.0\lib.d.ts" />

To avoid hardcoding the absolute path like that, you might want to make a local copy of lib.d.ts in your project in Scripts/typings/node, alongside node.d.ts.

You might also want to chime in on the discussion thread about this change on TypeScript forums, and share your experience with TS team.

نصائح أخرى

The simplest forceful fix :

var timer: NodeTimer;
timer = <any>setTimeout(somecallback, 1000);

Just for Fun

I created a small sample based on the current node definitions (https://github.com/borisyankov/DefinitelyTyped/blob/master/node/node.d.ts#L22) and it works fine in the typescript playground

interface NodeTimer{
    ref() : void;
    unref() : void;
}
declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeTimer;

var timer: NodeTimer;
timer = setTimeout(()=>{}, 1000);

I do not know why you are getting a conflict when I am not. FYI the conflicting setTimeout is defined in lib.d.ts but that is included in the TypeScript playground as well and isn't causing any drama.

If you have troubles with timeout like 'Cannot convert 'Number' to 'NodeTimer'' or 'Cannot convert 'Number' to 'NodeJS.Timer''or 'Cannot convert 'Number' to 'NodeJS.Timeout'' or Type 'Timeout' is not assignable to type 'number' while trying to use it in Browser »» Window and NodeJS, you can use this type-safe solution for Window and NodeJS both:

const timer: ReturnType<typeof setTimeout> = setTimeout(() => null, 1000);
clearTimeout(timer);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top