• Stars
    star
    229
  • Rank 174,666 (Top 4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 5 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Convert a new d.ts to one that works with older versions of Typescript

downlevel-dts rewrites .d.ts files created by any version of TypeScript so that they work with TypeScript 3.4 or later. It does this by converting code with new features into code that uses equivalent old features. For example, it rewrites accessors to properties, because TypeScript didn't support accessors in .d.ts files until 3.6:

declare class C {
  get x(): number;
}

becomes

declare class C {
  readonly x: number;
}

Note that not all features can be downlevelled. For example, TypeScript 4.0 allows spreading multiple tuple type variables, at any position in a tuple. This is not allowed in previous versions, but has no obvious downlevel emit, so downlevel-dts doesn't attempt to do anything. Be sure to test the output of downlevel-dts with the appropriate version of TypeScript.

Features

Here is the list of features that are downlevelled:

Omit (3.5)

type Less = Omit<T, K>;

becomes

type Less = Pick<T, Exclude<keyof T, K>>;

Omit has had non-builtin implementations since TypeScript 2.2, but became built-in in TypeScript 3.5.

Semantics

Omit is a type alias, so the downlevel should behave exactly the same.

Accessors (3.6)

TypeScript prevented accessors from being in .d.ts files until TypeScript 3.6 because they behave very similarly to properties. However, they behave differently with inheritance, so the distinction can be useful.

declare class C {
  get x(): number;
}

becomes

declare class C {
  readonly x: number;
}

Semantics

The properties emitted downlevel can be overridden in more cases than the original accessors, so the downlevel d.ts will be less strict. See the TypeScript 3.7 release notes for more detail.

asserts assertion guards (3.7)

TypeScript 3.7 introduced the asserts keyword, which provides a way to indicate that a function will throw if a parameter doesn't meet a condition. This allows TypeScript to understand that whatever condition such a function checks must be true for the remainder of the containing scope.

Since there is no way to model this before 3.7, such functions are downlevelled to return void:

declare function assertIsString(val: any, msg?: string): asserts val is string;
declare function assert(val: any, msg?: string): asserts val;

becomes

declare function assertIsString(val: any, msg?: string): void;
declare function assert(val: any, msg?: string): void;

Type-only import/export (3.8)

The downlevel emit is quite simple:

import type { T } from 'x';

becomes

import { T } from "x";

Semantics

The downlevel d.ts will be less strict because a class will be constructable:

declare class C {
}
export type { C };

becomes

declare class C {}
export { C };

and the latter allows construction:

import { C } from "x";
var c = new C();

type modifiers on import/export names (4.5)

The downlevel emit depends on the TypeScript target version and whether type and value imports/exports are mixed.

An import/export declaration with only import/export names that have type modifiers

import { type A, type B } from "x";
export { type A, type B };

becomes:

// TS 3.8+
import type { A, B } from "x";
export type { A, B };

// TS 3.7 or less
import { A, B } from "x";
export { A, B };

A mixed import/export declaration

import { A, type B } from "x";
export { A, type B };

becomes:

// TS 3.8+
import type { B } from "x";
import { A } from "x";
export type { B };
export { A };

// TS 3.7 or less
import { A, B } from "x";
export { A, B };

Semantics

When an import/export declaration has only import/export names with type modifiers, it is emitted as a type-only import/export declaration for TS 3.8+ and as a value import/export declaration for TS 3.7 or less. The latter will be less strict (see type-only import/export).

When type and value imports/exports are mixed, two import/export declarations are emitted for TS 3.8+, one for type-only imports/exports and another one for value imports/exports. For TS 3.7 or less, one value import/export declaration is emitted which will be less strict (see type-only import/export).

#private (3.8)

TypeScript 3.8 supports the new ECMAScript-standard #private properties in addition to its compile-time-only private properties. Since neither are accessible at compile-time, downlevel-dts converts #private properties to compile-time private properties:

declare class C {
  #private
}

It becomes:

declare class C {
  private "#private"`
}

Semantics

The standard emit for any class with a #private property just adds a single #private line. Similarly, a class with a private property adds only the name of the property, but not the type. The d.ts includes only enough information for consumers to avoid interfering with the private property:

class C {
  #x = 1
  private y = 2
}

emits

declare class C {
  #private
  private y
}

which then downlevels to

declare class C {
  private "#private";
  private y;
}

This is incorrect if your class already has a field named "#private". But you really shouldn't do this!

The downlevel d.ts incorrectly prevents consumers from creating a private property themselves named "#private". The consumers of the d.ts also shouldn't do this.

export * from 'x' (3.8)

TypeScript 3.8 supports the new ECMAScript-standard export * as namespace syntax, which is just syntactic sugar for two import/export statements:

export * as ns from 'x';

becomes

import * as ns_1 from "x";
export { ns_1 as ns };

Semantics

The downlevel semantics should be exactly the same as the original.

[named: number, tuple: string, ...members: boolean[]] (4.0)

TypeScript 4.0 supports naming tuple members:

type T = [foo: number, bar: string];

becomes

type T = [/** foo */ number, /** bar */ string];

Semantics

The downlevel semantics are exactly the same as the original, but the TypeScript language service won't be able to show the member names.

in out T (4.7)

Typescript 4.7 supports variance annotations on type parameter declarations:

interface State<in out T> {
    get: () => T;
    set: (value: T) => void;
}

becomes:

interface State<T> {
  get: () => T;
  set: (value: T) => void;
}

Semantics

The downlevel .d.ts omits the variance annotations, which will change the variance in the cases where they were added because the compiler gets it wrong.

Target

Since the earliest downlevel feature is from TypeScript 3.5, downlevel-dts targets TypeScript 3.4 by default. The downlevel target is configurable with --to argument.

Currently, TypeScript 3.0 features like unknown are not downlevelled, nor are there any other plans to support TypeScript 2.x.

Downlevel semantics

Usage

  1. $ npm install downlevel-dts
  2. $ npx downlevel-dts . ts3.4 [--to=3.4]
  3. To your package.json, add
"typesVersions": {
  "<4.0": { "*": ["ts3.4/*"] }
}
  1. $ cp tsconfig.json ts3.9/tsconfig.json

These instructions are modified and simplified from the Definitely Typed ones.

More Repositories

1

mini-typescript

A miniature model of the Typescript compiler, intended to teach the structure of the real Typescript compiler
TypeScript
1,142
star
2

vue-ts-plugin

Typescript Language Service Plugin for Vue
TypeScript
62
star
3

manual

Explanatory writing
51
star
4

fing

Fing: F# API Search
F#
38
star
5

minits

A miniature model of the Typescript compiler
F#
13
star
6

nltk

NLTK ported to Javascript
TypeScript
12
star
7

chatgpt-infer-ts-types

Use ChatGPT to infer Typescript types from Javascript code
TypeScript
8
star
8

vscode-wasm-typescript

Language server host for typescript using vscode's sync-api in the browser
TypeScript
7
star
9

dialect

Code for "A Statistical Method For Dialectometry"
Python
6
star
10

what-to-name-your-type

The most popular type names on Definitely Typed
JavaScript
4
star
11

elements-of-ai

Example implementations from Elements of Artificial Intelligence by Steven Tanimoto
TypeScript
4
star
12

dt-package-tester

Install @types packages and run their tests from Definitely Typed
JavaScript
4
star
13

typescript-history

A History of TypeScript
HTML
4
star
14

dt-perf

Scripts for analysing Definitely Typed performance on recent versions of Typescript
JavaScript
4
star
15

playground-dts-plugin

d.ts helper plugin for the Typescript playground
JavaScript
3
star
16

grafs

Cormen, Leiserson and Rivest's Introduction to Algorithms implemented in F#
F#
2
star
17

eoc

Essentials of Compilation
TypeScript
2
star
18

sandersn.github.io

Web site
1
star
19

dt-pr-prettier

Run prettier on Definitely Typed in a series of PRs
JavaScript
1
star
20

measure

Measure type system precision and recall of changes to Typescript
JavaScript
1
star
21

introduction-to-ai

Example implementations from Introduction to Artificial Intelligence by Charniak and McDermott
1
star
22

visual-basic

Ancient Visual Basic code I wrote when I was a teenager
VBA
1
star
23

recipes

Favourite recipes and tools to buy ingredients for them
JavaScript
1
star
24

pursuit-workshop

Pursuit open source workshop
1
star
25

typescript-version-replay

Test code with successive versions of Typescript
JavaScript
1
star
26

type_script

A toy compiler for a toy language
Rust
1
star