-
Notifications
You must be signed in to change notification settings - Fork 0
Using the Salsa Preview in Visual Studio 15 Preview
Visual Studio "15" Preview includes a preview of the new JavaScript language service, internally codenamed "Salsa". This may be switched on or off via a registry key.
Salsa also powers the JavaScript language service in VS Code, and most of the below info applies there also. See VSCode release notes for more info.
In the last few releases of Visual Studio, the JavaScript language service has been provided via an "execution based" model, which runs the code as you write it, and examines the execuction environment when it reaches the current editing location to provide information such as completion lists, signature help, etc. This provided a number of challenges, for example:
- Visual Studio specific: The existing language service is tied to Visual Studio and Windows, meaning it cannot be shared across editors & platforms (such as VS Code).
- Costly engineering: The bulk of the existing language service logic is written in C++, making iterating quickly and adding new features slower than desired.
- Inconsistent experience: Being execution based, changes in code in one location can impact the intellisense experience in other locations in non-obvious ways. Timeouts are also used to halt execution if paths take too long, which can cause different behavior on different hardware.
- No TypeScript integration: The current language service is entirely distinct from the TypeScript language service, meaning there is no shared context or integration across file types. Ideally TypeScript and JavaScript files should be able to contribute to each other's editing experience, and support similar JavaScript language features.
By basing the new JavaScript language service on the same codebase that powers the TypeScript language service, the following benefits are realized:
- The language service can be used outside of Visual Studio (as has been done by the VS Code team).
- The team can focus on one casebase written in TypeScript to provide parsing, checking, intellisense, etc., resulting in reduced cost, faster iteration, and a common experience across the languages.
- JavaScript and TypeScript files can be integrated within a project, including being aware of constructs across languages, and being emitted to downlevel code. (Features that are outlined below).
To enable the new "Salsa" language service experience in Visual Studio "15" Preview,
save the below as a local file named salsa.reg
and open it to update the registry.
(Set the same registry key value to 0 to disable at any point).
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\VisualStudio\15.0\TypeScriptLanguageService]
"UseTypeScriptExperimental"=dword:00000001
Now when you open a JavaScript file in Visual Studio, you should notice that
the editing experience is similar to that of TypeScript; namely richer types
flowing through constructs (as shown in the Array.map
example below), or support
for more recent language features (as shown in the destructuring example below).
Richer intellisense

Latest language features

The Salsa language service mostly uses the same inference as TypeScript to determine the type of a value. For a variable or property, this is typically the type of the value used to initialize it. For a function, the return type is inferred from the return statements, whereas the parameters are not inferred (but may be specified, as will be outlined later).
One common area where this can be limiting is in expando objects. These are objects that have properties added after initialization. For example:
var x = {a: true};
x.b = false;
x. // <- "x" is shown as only having the property "a" that it was initialized with
The type of x
can be specified explicitly to give it the desired type (as
outlined later).
For JavaScript files, some additional inference is done, specifically "es3-style" classes, and CommonJS-style module patterns are recognized. For example:
function Foo(param1) {
this.prop = param1;
}
Foo.prototype.getIt = function () { return this.prop; };
// Foo will appear as a class, and instances will have a 'prop' property and a 'getIt' method.
exports.Foo = Foo;
// This file will appear as an external module with a 'Foo' export.
// Note that assigning a value to "module.exports" is also supported.
Where type inference does not provide the desired type information, (or just for
documentation purposes), type information may be provided explicitly via JsDoc
annotations. For example, to give the variable x
the desired type in the example
above, it may be written as:
/**
* @type {{a: boolean, b: boolean, c: number}}
*/
var x = {a: true};
x.b = false;
x. // <- "x" is shown as having properties a, b, and c of the types specified
As mentioned, function parameters are also never inferred. Thus if it is desired that they have a specific type, then JsDoc may be used for this purpose also:
/**
* @param {string} param1 - The first argument to this function
*/
function Foo(param1) {
this.prop = param1; // "param1" (and thus "this.prop") are now of type "string".
}
See this doc for the JsDoc annotations currently supported.
With JavaScript and TypeScript now being based on the same language service, they
are able to interact in a richer way. For example, JavaScript intellisense can be
provided for values declared in a .d.ts
file. Types such as interface and classes
may also be declared in TypeScript, and those types are available for use in JsDoc
comments.
Below shows a simple example of a TypeScript definition file providing such type information (via an interface) to a JavaScript file in the same project (via a JsDoc tag).
TypeScript declarations used in JavaScript

In the TypeScript world, the most popular JavaScript libraries have their APIs
described by .d.ts
files, and the most common repository for such definitions
is on DefinitelyTyped.
With the Salsa language service enabled, it will by default try to detect which
JavaScript libraries are in use, and automatically download and reference the
corresponding .d.ts
file that describes the library in order to provide rich
intellisense. The files are downloaded to a cache located under the user folder
at %LOCALAPPDATA%\Microsoft\TypeScript
.
Currently auto-detection works for dependencies downloaded from NPM (via reading
the package.json
file) or Bower (via reading the bower.json
file).
Note: This feature currently only works in Salsa running within Visual Studio "15", and is not available in VS Code yet.
One of the key features TypeScript provides is the ability to use the latest JavaScript language features, and emit code that can execute in JavaScript runtimes that don't yet understand those newer features. With JavaScript using the same language service, it too can now take advantage of this same feature.
Before this can be set up, some understanding of the configuration options is
required. TypeScript is configured via a tsconfig.json
file. In the absense of such
a file, some default values are used. For compatibility reasons, these defaults are
different in a context where only JavaScript files (and optionally .d.ts
files)
are present. To compile JavaScript files, a tsconfig.json
file must be added,
and some of these defaults must then be set explicitly. The main settings of interest
are outlined below:
-
allowJs
: This value must be set totrue
for JavaScript files to be recognised. By default this isfalse
, as TypeScript compiles to JavaScript, and this is to avoid the compiler including files in just emitted. -
outDir
: This should be set to a location not included in the project, in order that the emitted JavaScript files are not detected and included in the project. -
module
: If using modules, this settings tells the compiler which module format the emitted code should use (e.g.commonjs
for Node or bundlers such as Browserify). -
exclude
: This setting states which folders not to include in the project. The output location, as well as non-project folders such asnode_modules
ortemp
, should be added to this setting. -
enableAutoDiscovery
: This setting enables the automatic detection and download of definition files as outlined above. -
compileOnSave
: This settings tells the compiler if it should recompile any time a source file is saved in Visual Studio.
In order to convert JavaScript files to CommonJS modules in an ./out
folder, settings
similar to the below might be included in a tsconfig.json
file.
{
"compilerOptions": {
"module": "commonjs",
"allowJs": true,
"outDir": "out"
},
"exclude": [
"node_modules",
"wwwroot",
"out"
],
"compileOnSave": true,
"typingOptions": {
"enableAutoDiscovery": true
}
}
With the above settings in place, if a source file (./app.js
) existed which
contains several ECMAScript 2015 language features as shown below:
import {Subscription} from 'rxjs/Subscription';
class Foo {
sayHi(name) {
return `Hi ${name}, welcome to Salsa!`;
}
}
export let sqr = x => x * x;
export default Subscription;
Then a file would be emitted to ./out/app.js
targetting ECMAScript 5 (the default)
that looks something like the below:
"use strict";
var Subscription_1 = require('rxjs/Subscription');
var Foo = (function () {
function Foo() {
}
Foo.prototype.sayHi = function (name) {
return "Hi " + name + ", welcome to Salsa!";
};
return Foo;
}());
exports.sqr = function (x) { return x * x; };
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = Subscription_1.Subscription;
//# sourceMappingURL=app.js.map
With the above configuration file in place, TypeScript and JavaScript files may be used in the same compilation. For example, existing JavaScript code using the CommonJS module format, may be imported and consumed by TypeScript code using the ECMAScript 2015 module syntax. Conversely, TypeScript code written to provide a well-defined API contract for a service, may be referenced by JavaScript code that is written to call that service, thus providing rich intellisense at design time.
The new JavaScript language service adds rich support for the JSX syntax, and also for converting the syntax to React API calls - as it does for TSX files.
Note: To convert the JSX syntax to React calls, the setting "jsx": "react"
must
be added to the compilerOptions
in the tsconfig.json
file outlined above.
Again, with the ability to mix and match, it is possible to define React components with a well defined type in a TypeScript file (.tsx), and then use those components from a .jsx file. (Note: Mixing languages is not required here, you could write entirely in JavaScript or TypeScript, the example is to highlight the flexibilty provided).
The below screen-shot shows a React component defined in the comps.tsx
TypeScript
file, and then this component being used from the app.jsx
file, complete with
intellisense for completions and documentation within the JSX expressions.

The JavaScript file created at `./out/app.js' upon build is shown below:
"use strict";
var comps_1 = require('./comps');
var x = React.createElement(comps_1.RepoDisplay, {description: "test"});
- If compiling only JavaScript files, then MSBuild does not detect that there is input source for the TypeScript compiler. To workaround this problem, add one TypeScript file to the project.
- Sometime changes to configuration, such as adding or editing a
tsconfig.json
file, are not picked up correctly. Reloading the project (or restarting Visual Studio) should pick up the changes correctly.
TypeScript Language Basics
- Basic Types
- Interfaces
- Classes
- Namespaces and Modules
- Functions
- Generics
- Compiler Options
- tsconfig.json
- Integrating with Build Tools
- Nightly Builds
TypeScript Language Advanced
- Mixins
- Declaration Merging
- Type Inference
- Type Compatibility
- JSX
- Writing Declaration Files
- Typings for NPM packages
News
TypeScript Contributors
- Contributing to TypeScript
- TypeScript Design Goals
- Coding Guidelines
- Spec conformance testing
- Useful Links for TypeScript Issue Management
- Writing Good Design Proposals
- Compiler Internals
Building Tools for TypeScript
- Architectural Overview
- Using the Compiler API
- Using the Language Service API
- Dev Mode in Visual Studio
- Debugging Language Service in VS Code
FAQs