sandersn / downlevel-dts Goto Github PK
View Code? Open in Web Editor NEWConvert a new d.ts to one that works with older versions of Typescript
License: MIT License
Convert a new d.ts to one that works with older versions of Typescript
License: MIT License
Node 18.7.0
TypeScript 4.8.2
Worked in downlevel-dts
v 0.10.0; broken in 0.10.1
/home/ntucker/src/rest-hooks/node_modules/downlevel-dts/node_modules/typescript/lib/typescript.js:28803
➤ YN0000: return node.kind === 162 /* ComputedPropertyName */;
➤ YN0000: ^
➤ YN0000:
➤ YN0000: TypeError: Cannot read properties of undefined (reading 'kind')
➤ YN0000: at Object.isComputedPropertyName (/home/ntucker/src/rest-hooks/node_modules/downlevel-dts/node_modules/typescript/lib/typescript.js:28803:21)
➤ YN0000: at Object.createPropertyDeclaration (/home/ntucker/src/rest-hooks/node_modules/downlevel-dts/node_modules/typescript/lib/typescript.js:23287:20)
➤ YN0000: at transform (/home/ntucker/src/rest-hooks/node_modules/downlevel-dts/index.js:96:20)
➤ YN0000: at visitNodes (/home/ntucker/src/rest-hooks/node_modules/downlevel-dts/node_modules/typescript/lib/typescript.js:89111:48)
➤ YN0000: at Object.visitEachChild (/home/ntucker/src/rest-hooks/node_modules/downlevel-dts/node_modules/typescript/lib/typescript.js:89579:362)
➤ YN0000: at transform (/home/ntucker/src/rest-hooks/node_modules/downlevel-dts/index.js:374:15)
➤ YN0000: at visitNodes (/home/ntucker/src/rest-hooks/node_modules/downlevel-dts/node_modules/typescript/lib/typescript.js:89111:48)
➤ YN0000: at visitLexicalEnvironment (/home/ntucker/src/rest-hooks/node_modules/downlevel-dts/node_modules/typescript/lib/typescript.js:89151:22)
➤ YN0000: at Object.visitEachChild (/home/ntucker/src/rest-hooks/node_modules/downlevel-dts/node_modules/typescript/lib/typescript.js:89702:55)
➤ YN0000: at transform (/home/ntucker/src/rest-hooks/node_modules/downlevel-dts/index.js:374:15)
- import type {Something} from 'somewhere';
# import {Something} from 'somewhere';
Original d.ts
export { WebResource }
Generated d.ts
export { WebResource };
This is pretty minor, not sure that it hurts anything, but noticed it when looking at diffs.
It would be very cool if this project would support stripping down variance annotations that were introduced recently in microsoft/TypeScript#48240
3.7 d.ts:
/**
* Gets the lease Id.
*
* @readonly
* @memberof BlobLeaseClient
* @type {string}
*/
get leaseId(): string;
Generated downlevel d.ts:
readonly leaseId: string;
Would be nice to preserve these comments for IntelliSense
there is missing support for template literal types introduced in TS 4.1
export declare type Greeting = `hello ${World}`
declare type World = 'world'
↓↓↓ downlevel-dts
↓↓↓
export declare type Greeting = `hello ${World}`
declare type World = 'world'
export declare type Greeting = `hello ${World}`
declare type World = 'world'
↓↓↓ downlevel-dts
↓↓↓
// Good enough
export declare type Greeting = string
// This would be awesome
export declare type Greeting = `hello world`
declare type World = 'world'
IteratorResult<T, T>
For TS version < 3.6, IteratorResult
takes only one argument -> IteratorResult<T>
.
For TS version >= 3.6, IteratorResult
takes two arguments -> IteratorResult<T, TReturn = any>
(the second one is optional).
TSC compilation would fail for TS version<3.6 when used IteratorResult<T, T>
.
IteratorResult
in version 3.9interface IteratorYieldResult<TYield> {
done?: false;
value: TYield;
}
interface IteratorReturnResult<TReturn> {
done: true;
value: TReturn;
}
type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
IteratorResult
in version 3.3interface IteratorResult<T> {
done: boolean;
value: T;
}
It seems appropriate to downlevel IteratorResult<T, T>
(or even IteratorResult<T, TReturn>) to IteratorResult<T>
.
TS 4.1 adds support for export * as default from 'foo'
. This should downlevel to two statements:
import * as _x from 'foo'
export default _x
export declare class C {
#private: string;
}
Proposed emit
declare const private: unique symbol;
export declare class C {
private [private]: string
}
[email protected] introduce new readonly array & readonly tuple syntax. It generates keyword 'readonly' that's not supported before 3.4. So why not downlevel it to make .d.ts compatible with 3.0~3.4.
If an input d.ts has a reference directive like
/// <reference types="node" />
then that line will appear twice in the output d.ts:
/// <reference types="node" />
/// <reference types="node" />
Or at least running on multiple directories.
I've added this module to jest (super grateful it exists!), but I have to call downlevel-dts
in all the directories in the monorepo (I currently loop through all directories and spawn inside each). It'd be awesome if I could pass a list of all the projects I want to build in addition to the paths
➤ YN0000: DeprecationWarning: 'createExportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createExportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createImportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createPropertyDeclaration' has been deprecated since v4.8.0. Decorators have been combined with modifiers. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createExportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createExportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createImportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createPropertyDeclaration' has been deprecated since v4.8.0. Decorators have been combined with modifiers. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createExportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createExportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createImportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createExportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createImportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createExportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createExportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createExportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createImportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createImportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createNamedImports' has been deprecated since v4.0.0. Use the appropriate method on 'ts.factory' or the 'factory' supplied by your transformation context instead.
➤ YN0000: DeprecationWarning: 'createImportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createImportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
➤ YN0000: DeprecationWarning: 'createExportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decorators' parameter.
Reference: https://github.com/microsoft/TypeScript/wiki/API-Breaking-Changes
One big difference in the downlevel output is there aren't any map files.
Maybe it's too out of scope, since the original offsets would no longer line up?
as const
released in 3.4 makes dealing with constant strings and numbers much easier for library authors. Unfortunately, we have not been able to adopt it and also support typescript <3.4 users. It would be great if this could support down leveling as const
.
Currently, I end up doing something like this . Enums are ok for internal usage, but const objects with as const
are my preference for publicly exported values. It allows users to easily supply literal values where we expect a union of possible values.
Is there any reason for it? Currently it means locally, every CI build, every single build of anyone using the AWS CDK we pull down a Typescript nightly. This is a huge amount of energy, bandwidth, etc etc that is just burned because of a config issue or error.
What TS should this be targeting or is it deliberately TS next despite not supporting Typescript 5?
import { RawSourceMap } from 'source-map';
interface FixedRawSourceMap extends Omit<RawSourceMap, 'version'> {
version: number;
}
Output:
import { RawSourceMap } from 'source-map';
interface FixedRawSourceMap extends Omit<RawSourceMap, 'version'> {
version: number;
}
Using 0.4.0
Workaround:
import { RawSourceMap } from 'source-map';
type SourceMapWithVersion = Omit<RawSourceMap, 'version'>;
interface FixedRawSourceMap extends SourceMapWithVersion {
version: number;
}
We run downlevel-dts as instructed here, with: downlevel-dts . ts3.4 && cp tsconfig.json ./ts3.4/
, but on subsequent runs this causes the ./ts3.4 folder to be read as input and then included in the output folder.
We get something like
.
├── lib
├── ...
├── ts3.4
│ ├── ...
│ ├── ts3.4
│ │ ├── ...
│ │ ├── ts3.4
Seems like downlevel-dts should exclude the output folder from its inputs.
Error: Debug Failure. Unhandled SyntaxKind: ImportClause.
Error: Debug Failure. Unhandled SyntaxKind: NamedExports.
export const foo: (_: number | string) => asserts _ is number = (_) => {};
export declare const foo: (_: number | string) => asserts _ is number;
export function foo(_: number | string): asserts _ is number {}
node | 12.18.2 |
downlevel-dts | 0.6.0 |
command | node_modules/.bin/downlevel-dts dist/my-package dist/my-package/ts3.4 --to=3.4 |
I have a project that puts typings into a folder like:
\typings\latest\src\foo.d.ts
\typings\latest\test\bar.d.ts
I try running downlevel-dts against this folder like so npx downlevel-dts typings\latest typings\3.4
I end up with a typings\3.4
folder, but besides having src
and test
, it also has a path that looks like the path in my monorepo down to where my package.json is (with some of the beginning chopped off):
typings\3.4\dk-for-js\sdk\storage\storage\blob\typings\latest\...
With typescript 4 we want to make 3 versions of our builds, normal dist with latest (4+) and allso 3.4 and 3.8 versions like:
"typesVersions": {
"<3.8": {
"*": [
"ts3.4/*"
]
},
">=3.8 <4.0": {
"*": [
"ts3.8/*"
]
}
},
And the build script:
"build": "tsc && downlevel-dts . ts3.4 --to=3.4 && cp tsconfig.json ./ts3.4/ && downlevel-dts . ts3.8 --to=3.8 && cp tsconfig.json ./ts3.8/ && rm -rf ./ts3.8/ts3.4",
Note: I have to remove files from ts3.4 in previous step ending up in ts3.8
If you see anything I did wrong with this I whould love to know. Else it whould be great with an optional argument that excempts files that we do not want to end up in the target.
This is a spin-off of the discussion started in #23. Theoretically it would be possible for this tool to modify the typesVersions
entry of a package.json file automatically depending on the features used.
If for example no feature is used which requires any down-leveling no typesVersions
property could be created at all.
If for example a private field is used in the codebase downlevel-dts could create a folder with the down-leveled files and at the same time it could update the typesVersions
entry to point to that folder.
If for example a private field and accessors are used in the same codebase downlevel-dts could create two folders with the down-leveled files for TypeScript below 3.8 and for TypeScript below 3.7. It could also update the typesVersions
entry to point to those two folders.
Hey Nathan,
Thanks for the tweet and this is an excellent use case for the library!
I noticed a few things that might improve this:
GetAccessorDeclaration#getSetAccessor()
helper method. This will help you get the set accessor for a get accessor. A similar method exists on SetAccessorDeclaration
. I actually went to look at these methods just a little while ago though and there were a few bugs in them (one of the first methods I wrote in the library). Upgrade to ts-morph 4.3.1 and those issues are fixed (it didn't work outside class declarations and didn't check if isStatic()
was equal for both of the nodes). I just did a release right now.f.copy(...)
will return the copied source file, so you could copy first then modify that source file. That will save an additional trip to the file system.TODO: Just thought of this, but replaceWithText
will also replace the js docs so we need to also include those here.
Also, perhaps I should add a toProperty()
method in ts-morph that would change get and set accessors to either property declarations or property assignments depending on the parent.
TS 4.5 added type
modifiers on import names which is a great syntax improvement IMO. To adopt this feature more quickly in a library, declaration files need to be downleveled to a compatible syntax:
type
modifiersRepro (bash):
echo 'export type A = [one: 1, two: [three: 3, four: 4]]' > test.d.ts
npx [email protected] test.d.ts out.d.ts
cat out.d.ts
Result:
export type A = [
/*one*/ 1,
/*two*/ [
three: 3,
four: 4
]
];
Expected:
export type A = [
/*one*/ 1,
/*two*/ [
/*three*/ 3,
/*four*/ 4
]
];
This can be worked around by running downlevel-dts
multiple times, but it's hard to know how many!
Something like npx downlevel-dts . ts3.4
doesn't work at the moment, because the version of the package that is published on NPM doesn't have "bin": "index.js",
in its package.json.
Instead you get an error: command not found: downlevel-dts
I'm working on an RFC for how we manage Ember's ecosystem-wide SemVer commitments and TS together (🎉) and one of the elements I'm designing in the midst of it is the use of downlevel-dts
to handle breaking changes across minor versions of TS. The current approach of supporting 3.4+ is good enough to get the job done (and in my testing so far, I really appreciate downlevel-dts
's level of "it just works"!)—but what we'd really like to be able to do is generate a .d.ts
file for each TS version in a given package's support matrix, so that given a set of source files, you'd do something like this:
yarn downlevel-dts --to=3.6 . ts3.6
yarn downlevel-dts --to=3.7 . ts3.7
yarn downlevel-dts --to=3.8 . ts3.8
Deciding automatically which need to be built, a la #26, would also be super neat, but having this level of granularity for us would be really helpful. In particular, we'd prefer that making a change to support a new version of TS doesn't entail changing the types published for users who haven't upgraded TS yet.
For example: we'd really prefer that when 3.8 added support for type-only imports and exports, our emit for 3.7 consumers didn't revert from get
semantics to readonly
semantics.
If there's interest, I'm very happy to do the implementation work. Having read the source, it looks to be neither trivial nor extremely difficult, and it would be extremely valuable for our use case!
declare abstract class DefinitionBase<TType extends string> {}
declare abstract class DefinitionBase<TType extends string> {}
declare abstract class DefinitionBase< extends string> {}
Typescript 4.5 has introduced the Awaited type, which recursively extracts the value inside a promise.
I wanted to contribute to this library, but I got confused about how to implement it since it calls itself:
type Awaited<T> =
T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode
T extends object & { then(onfulfilled: infer F): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped
F extends ((value: infer V, ...args: any) => any) ? // if the argument to `then` is callable, extracts the first argument
Awaited<V> : // recursively unwrap the value
never : // the argument to `then` was not callable
T; // non-object or non-thenable
I was able to downlevel it from:
export type K<T> = Awaited<Promise<T>>;
to
export type K<T> = T extends null | undefined ? T : T extends object & {
then(onfulfilled: infer F): any;
} ? F extends ((value: infer V, ...args: any) => any) ? Awaited<V> : never : T;
As you can see, Awaited calls itself recursively. I tried to look for different similar types that call themselves recursively, but I found none.
I'll be happy to create a PR for this, but I'm not sure how to proceed from here.
You can see here my current attempt.
I recently came across an issue with this package where JSDoc comments in getters would get incorrectly downleveled and become regular multi-line comments, which lose all the properties of a JSDoc comment. Here's an example of that taken from the bson package
declare class ObjectId {
/**
* The generation time of this ObjectId instance
* @deprecated Please use getTimestamp / createFromTime which returns an int32 epoch
*/
get generationTime(): number;
set generationTime(value: number);
}
becomes
declare class ObjectId {
/*
* The generation time of this ObjectId instance
* @deprecated Please use getTimestamp / createFromTime which returns an int32 epoch
*/
generationTime: number;
}
export * as TSESTree from './ts-estree';
import * as TSESTree from './ts-estree';
export { TSESTree };
import * as TSESTree_1 from './ts-estree';
export { TSESTree_1 as TSESTree } from './ts-estree';
See also
Test input:
Lines 27 to 28 in ca924f6
Incorrect test output:
downlevel-dts/baselines/ts3.4/test.d.ts
Lines 24 to 26 in ca924f6
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.