Feature request: Preprocessor directives in typescript like #DEBUG, and a #NAMEOF function

Topics: Code Checkins, Language Specification
Jan 29, 2014 at 8:20 AM
Edited Jan 29, 2014 at 8:25 AM
I use typescript to develop a RIA framework. A common thing in this kind of frameworks is an observable pattern. Also, there's a need to debug the code we write.
For the first case now i use literal strings for property names like in the next code:
  set dataSource(v: collMod.BaseCollection<collMod.CollectionItem>) {
                    if (this._dataSource !== v) {
                        if (!!this._dataSource)
                            this._tempValue = this.selectedValue;
                        if (!!this._dataSource)
                            this._unbindDS();
                        this._dataSource = v;
                        if (!!this._dataSource) {
                            this._bindDS();
                        }
                        this._refresh();
                        if (!!this._dataSource)
                            this._tempValue = undefined;
                        this.raisePropertyChanged('dataSource');
                        this.raisePropertyChanged('selectedItem');
                        this.raisePropertyChanged('selectedValue');
                    }
                }
On refactoring, i can change property names, and then i need to find everywhere i used those property names. #NAMEOF function can solve this problem.
I could write the above code like this:
 set dataSource(v: collMod.BaseCollection<collMod.CollectionItem>) {
                    if (this._dataSource !== v) {
                        if (!!this._dataSource)
                            this._tempValue = this.selectedValue;
                        if (!!this._dataSource)
                            this._unbindDS();
                        this._dataSource = v;
                        if (!!this._dataSource) {
                            this._bindDS();
                        }
                        this._refresh();
                        if (!!this._dataSource)
                            this._tempValue = undefined;
                        this.raisePropertyChanged(#NAMEOF(this.dataSource));
                        this.raisePropertyChanged(#NAMEOF(this.selectedItem));
                        this.raisePropertyChanged(#NAMEOF(this.selectedValue));
                    }
                }
The compiler on compilation will replace an expression like
#NAMEOF(this.dataSource)
with
'dataSource'
Also #NAMEOF can be used to obtain class names from expression like:
#NAMEOF(SomeClass)
Another problem is a code debugging.
It would be good to have a preprocessor directive like #if, #elseif and etc.
Using them a programmer could imbed debugging code into the program and it won't be in the release version compiler's output. Instead, now we need to imbed code like this:
 if (base_utils.isUndefined(nextObj)) {
                                if (DebugLevel == DEBUG_LEVEL.HIGH) {
                                    debugger;
                                }
                                if (DebugLevel > DEBUG_LEVEL.NONE) {
                                    global._onUnResolvedBinding(BindTo.Target, self.target, self._tgtPath.join('.'), path[0]);
                                }
This code goes to the compiler output, even if it is not needed in the release version.
Jan 30, 2014 at 6:52 PM
Conditional compilation has been suggested several times, see my comment in the issue tracker: https://typescript.codeplex.com/workitem/111#CommentContainer9

If you want to get the name of class as a string you can use the "name" property of the constructor. Unfortunately TS definitions do not export it and it's available only in non-IE browsers but it may be useful. It works like that:
class Person {
}

var cls = Person;
var name = cls['name'];
alert(name);
See working example here: http://www.typescriptlang.org/Playground/#src=class%20Person%20%7B%0A%7D%0A%0Avar%20cls%20%3D%20Person%3B%0Avar%20name%20%3D%20cls%5B'name'%5D%3B%0Aalert(name)%3B

And the reference documentation (with a big warning) here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
Jan 31, 2014 at 9:05 AM
@wiktork, thanks for reply.
I know the issue about conditional compilation. Bu i wanted to add it also to a discussion.

P.S. I also would be glad to see a method in typescript to obtain a module name from the module reference.
The compiler knows this information, so there should be a way to expose this in typescript language.
Jan 31, 2014 at 9:12 AM
as to @johnturner reply to the issue.
AMD loading does not solve the problem of removing code from release version.
You just need to have two modules for debug and release. It is difficult to maintain.
Why always to seek for complex solutions, instead of implementing a straightforward one?
The thing should be solved with one tool, not a set of different teks.
Jan 31, 2014 at 8:47 PM
I agree with @BBGONE and would like to see support for pre-processor directives.

There are definitely many workarounds, including the one suggested by @wiktork for RequireJS and an equivalent one for ASP.NET
          ///#DEBUG
              // This will be removed by the minifier in release mode
          ///#ENDDEBUG
I consider this a horrible blemish on the shiny codebase that is possible with TypeScript - it brings back painful memories of JSLint, and sometimes has me waking in a cold sweat in the middle of the night.

Hope it gets fixed!
Feb 1, 2014 at 9:59 AM
To @everyone
It is interesting to read how many users ask the same question on the dart team.
https://groups.google.com/a/dartlang.org/forum/#!topic/misc/i81bRYO7eew

The Dart also have no preprocessor directives.
And some people even stupidly suggest to use a cpp precompiler to attain the goal.
But the question was simple:
@Ladislav Thon
>> You can run cpp (the C preprocessor) on any file, even a Dart source code. So you can do this
>> today, without any issues.

Again you're kidding?
Please explain me in a maximum five steps how I can use this today without any trick.

#if WEB_CLIENT
#error Illegal use of this library in the web client
#end

Limitation to you.
If I can not use it after about five minutes after your answering then your answer will be not accepted.

Another restrictions.
1. Do not offer to setup C preprocessor because this approach will not work where it (preprocessor) is not present.
2. Do not offer to set manually directive WEB_CLIENT because many people are lazy.
The Dart team are stubborn to introduce this feature.
But the dart compile has a tree shaking feature, but typescript does not have it.
http://stackoverflow.com/questions/20288002/is-there-a-compiler-preprocessor-in-dart

I don't believe that the teams are very reluctant to introduce it into their compilers.
Feb 1, 2014 at 11:38 AM
@BBGONE The "debugger" statement can be removed during minification with UglifyJS2: https://github.com/mishoo/UglifyJS2#compressor-options (drop_debugger)
The same can be done for console.* calls (drop_console - like console.assert(typeof nextObj !== 'undefined', 'nextObj is undefined!') ). With "break on errors" turned on it gives pretty nice development assertions that are disabled in production build. They're not true build directives - I know - but well... beggars can't be choosers!

By the way using cpp processor on Dart source code.... LOL! :)
Feb 4, 2014 at 7:53 PM
Given how easy this feature must be to implement, and how many people have requested it in the forums - I am really surprised at the resistance from the TypeScript team.