On this page
TypeScript support
TypeScript is a first class language in Deno, just like JavaScript or WebAssembly, you can run or import TypeScript without installing anything more than the Deno CLI. With its built-in TypeScript compiler, Deno will compile your TypeScript code to JavaScript with no extra config needed, making your development process a breeze.
Type Checking Jump to heading
One of the main advantages of TypeScript is that it can make your code type safe, catching errors during development rather than runtime. TypeScript is a superset of JavaScript meaning that syntactically valid JavaScript becomes TypeScript with warnings about being "unsafe".
Deno type checks TypeScript in strict mode
by default, the TypeScript core
team
recommends strict mode as a sensible default.
Deno allows you to type-check your code (without executing it) with the
deno check
subcommand:
deno check module.ts
# or also type check remote modules and npm packages
deno check --all module.ts
Type checking can take a significant amount of time, especially if you are working on a codebase where you are making a lot of changes. Deno optimizes type checking, but it still comes at a cost. Therefore, by default, TypeScript modules are not type-checked before they are executed.
When using the deno run
command, Deno will skip type-checking and run the code
directly. In order to perform a type check of the module before execution
occurs, you can use the --check
flag with deno run
:
deno run --check module.ts
# or also type check remote modules and npm packages
deno run --check=all module.ts
When Deno encounters a type error, the process with exit before executing the
code. If you have used the --check
flag then type-related diagnostics will
prevent the program from running: it will halt on these warnings, and exit the
process before executing the code.
In order to avoid this, you will either need to resolve the issue, use the
// @ts-ignore
or // @ts-expect-error
pragmas, or skip type checking all
together.
When testing your code, type checking is enabled by default, you can use the
--no-check
flag to skip type checking if preferred:
deno test --no-check
Determining the type of file Jump to heading
Since Deno supports JavaScript, TypeScript, JSX, TSX modules, Deno has to make a
decision about how to treat each of these kinds of files. For local modules,
Deno makes this determination based on the extension. When the extension is
absent in a local file, it is assumed to be JavaScript. The module type can be
overridden using the --ext
argument. This is useful if the module does not
have a file extension, e.g. because it is embedded in another file.
A .d.ts
file and a .ts
file have different semantics in TypeScript and
different ways they need to be handled in Deno. While we expect to convert a
.ts
file into JavaScript, a .d.ts
file contains no "runnable" code, it is
simply describing types. When Deno fetches a remote module, the media type for a
.ts.
and .d.ts
file looks the same. So the path is checked, if a file has a
path that ends with .d.ts
it will be treated as type definition only file
instead of "runnable" TypeScript.
Supported media types Jump to heading
The following table provides a list of media types which Deno supports when identifying the type of file of a remote module:
Media Type | How File is Handled |
---|---|
application/typescript |
TypeScript (with path extension influence) |
text/typescript |
TypeScript (with path extension influence) |
video/vnd.dlna.mpeg-tts |
TypeScript (with path extension influence) |
video/mp2t |
TypeScript (with path extension influence) |
application/x-typescript |
TypeScript (with path extension influence) |
application/javascript |
JavaScript (with path extensions influence) |
text/javascript |
JavaScript (with path extensions influence) |
application/ecmascript |
JavaScript (with path extensions influence) |
text/ecmascript |
JavaScript (with path extensions influence) |
application/x-javascript |
JavaScript (with path extensions influence) |
application/node |
JavaScript (with path extensions influence) |
text/jsx |
JSX |
text/tsx |
TSX |
text/plain |
Attempt to determine that path extension, otherwise unknown |
application/octet-stream |
Attempt to determine that path extension, otherwise unknown |
Mixing JavaScript and TypeScript Jump to heading
By default, Deno does not type check JavaScript. Check out the documentation on configuring your project to find out more about how to configure your project to do this. Deno does support JavaScript importing TypeScript and TypeScript importing JavaScript.
An important note though is that when type checking TypeScript, by default Deno will "read" all the JavaScript in order to be able to evaluate how it might have an impact on the TypeScript types. The type checker will do the best it can to figure out the types of the JavaScript you import into TypeScript, including reading any JSDoc comments. Details of this are discussed in detail in the Types and type declarations section.
Type resolution Jump to heading
Deno adheres to a design principle of no non-standard module resolution, meaning it deals with explicit module specifiers. This can cause issues when importing JavaScript files that have corresponding type definition files. To address this, Deno offers these solutions:
-
Provide types when importing to ensure that TypeScript uses the specified type definition file for type checking. Use the
@ts-types
compiler hint to specify a type definition file for a JavaScript module:// @ts-types="./coolLib.d.ts" import * as coolLib from "./coolLib.js";
-
Provide types when hosting. Use the
@ts-self-types
pragma in the JavaScript file to point to the type definition file:// @ts-self-types="./coolLib.d.ts"
This informs Deno to use the type definition file for type checking while still loading the JavaScript file for execution.
- Using HTTP headers for remote modules. Deno supports a header for remote
modules that instructs the runtime on where to locate the types for a given
module. For example, a response for
https://example.com/coolLib.js
might look like this:
HTTP/1.1 200 OK
Content-Type: application/javascript; charset=UTF-8
Content-Length: 648
X-TypeScript-Types: ./coolLib.d.ts
When seeing this header, Deno would attempt to retrieve
https://example.com/coolLib.d.ts
and use that when type checking the original
module.
Using ambient or global types Jump to heading
Using module/UMD type definitions with Deno is generally preferred, as it allows
a module to explicitly import the types it depends on. Modular type definitions
can augment the global scope using declare
global. For example:
declare global {
var AGlobalString: string;
}
This makes AGlobalString
available globally when the type definition is
imported.
However, when using existing type libraries, it might not always be possible to use modular type definitions. In such cases, there are methods to include arbitrary type definitions during type checking.
Using a triple-slash directive Jump to heading
You can couple type definitions directly to the code by adding a triple-slash types directive in a TypeScript file. This includes the type definition during type checking. For example:
/// <reference types="./types.d.ts" />
The specifier can be a relative path or a fully qualified URL:
/// <reference types="https://deno.land/x/pkg@1.0.0/types.d.ts" />
Using a configuration file Jump to heading
Another option is to use a configuration file to include type definitions by specifying a "types" value in the "compilerOptions". For example:
{
"compilerOptions": {
"types": [
"./types.d.ts",
"https://deno.land/x/pkg@1.0.0/types.d.ts",
"/Users/me/pkg/types.d.ts"
]
}
}
Relative specifiers in the "types" array are resolved relative to the config
file’s path. Use the --config=path/to/file
flag to tell Deno to use this
configuration file.
Type Checking Web Workers Jump to heading
When Deno loads a TypeScript module in a web worker, it automatically type
checks the module and its dependencies against the Deno web worker library. In
contexts such as deno cache
or in editors you may want to instruct Deno to use
the web worker library. You can do this a couple of ways:
Using triple-slash directives Jump to heading
This option couples the library settings with the code itself. By adding the following triple-slash directives near the top of the entry point file for the worker script, Deno will type check it as a Deno worker script, irrespective of how the module is analyzed:
/// <reference no-default-lib="true" />
/// <reference lib="deno.worker" />
- The first directive ensures no other default libraries are used, preventing conflicting type definitions.
- The second directive instructs Deno to apply the built-in Deno worker type definitions and dependent libraries.
These directives help Deno automatically detect and apply the correct libraries during type checking when using commands like deno cache or deno bundle, or when using an IDE with the Deno language server. However, this approach makes the code less portable to non-Deno platforms like tsc, as only Deno includes the "deno.worker" library.
Using a configuration file Jump to heading
Another option is to use a configuration file that is configured to apply the library files. A minimal file that would work would look something like this:
{
"compilerOptions": {
"target": "esnext",
"lib": ["deno.worker"]
}
}
Then when running a command on the command line, you would need to pass the
--config path/to/file
argument, or if you are using an IDE which leverages the
Deno language server, set the deno.config
setting.
If you also have non-worker scripts, you will either need to omit the --config
argument, or have one that is configured to meet the needs of your non-worker
scripts.
Important points Jump to heading
Type Declaration Semantics Jump to heading
-
Type declaration files (
.d.ts files
) in Deno are treated as module declarations (UMD) rather than ambient/global declarations. -
Importing within type declarations follows Deno’s normal import rules, which may cause compatibility issues with some
.d.ts
files available online. -
The CDN esm.sh provides type declarations by default, which can be disabled by appending
?no-dts
to the import URL.
Behavior of JavaScript When Type Checking Jump to heading
-
When importing JavaScript into TypeScript in Deno, the TypeScript compiler performs static analysis on the JavaScript module to determine the shape of its exports, even if
checkJs
is set tofalse
. -
This can cause issues with modules that have special packaging or are global UMD modules, leading to misleading errors. Providing types using one of the mentioned methods can help.