Repository: sandersn/downlevel-dts
Pull request #48 (2020-11-17 04:54:12)

Downlevel type alias function assertions
Properly downlevels `type Foo<T> = (val: unknown) => asserts val is T` to `type Foo<T> = (val: unknown) => void`

I also added a debug file for VSCode devs. It makes it a little easier to get started debugging the tests. Happy to remove that if you don't want to include it in the project!

I discovered this issue while writing some type assertions today (see relevant changes [here](https://github.com/microsoft/botbuilder-js/pull/3066/files#diff-9b546a3a8b1030340c9c20edc96fc3f7bb3b3dd69c942d7b8b393f16a5727d3b)). The files produced by `downlevel-dts` failed to compile in older Typescript versions. This should fix the two cases I ran into.

joshgummersall: Just verified that this produces valid output for the use case linked in the PR description. I've published `@standardlabs/downlevel-dts` to use in the meantime. Thanks for the great tool!
joshgummersall: @sandersn I've also added a checksum feature: https://github.com/sandersn/downlevel-dts/compare/master...joshgummersall:checksum

That package is published as `@standardlabs/downlevel-dts@0.7.3` if you want to give it a test drive. I'll happily submit a PR for that, as well, if and when this PR lands. I'm testing it (with exciting results) against the `botbuilder-js` codebase as I write this comment.

Patch:
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..7096bcc
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,17 @@
+{
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "npm test",
+      "type": "node",
+      "protocol": "inspector",
+      "request": "launch",
+      "cwd": "${workspaceFolder}",
+      "runtimeExecutable": "npm",
+      "runtimeArgs": ["test"],
+      "stopOnEntry": false,
+      "env": {},
+      "sourceMaps": true
+    }
+  ]
+}
diff --git a/index.js b/index.js
index 07f8d6f..a9456eb 100644
--- a/index.js
+++ b/index.js
@@ -61,23 +61,23 @@ function doTransform(checker, targetVersion, k) {
    * @return {import("typescript").VisitResult<Node>}
    */
   const transform = function(n) {
-    if (
-      semver.lt(targetVersion, "3.7.0") &&
-      ts.isFunctionDeclaration(n) &&
-      n.type &&
-      ts.isTypePredicateNode(n.type) &&
-      n.type.assertsModifier
-    ) {
-      return ts.createFunctionDeclaration(
-        n.decorators,
-        n.modifiers,
-        n.asteriskToken,
-        n.name,
-        n.typeParameters,
-        n.parameters,
-        ts.createTypeReferenceNode("void", undefined),
-        n.body
-      );
+    if (semver.lt(targetVersion, "3.7.0")) {
+      if (ts.isFunctionTypeNode(n) && n.type && ts.isTypePredicateNode(n.type) && n.type.assertsModifier) {
+        return ts.createFunctionTypeNode(n.typeParameters, n.parameters, ts.createTypeReferenceNode("void", undefined));
+      }
+
+      if (ts.isFunctionDeclaration(n) && n.type && ts.isTypePredicateNode(n.type) && n.type.assertsModifier) {
+        return ts.createFunctionDeclaration(
+          n.decorators,
+          n.modifiers,
+          n.asteriskToken,
+          n.name,
+          n.typeParameters,
+          n.parameters,
+          ts.createTypeReferenceNode("void", undefined),
+          n.body
+        );
+      }
     }
 
     if (semver.lt(targetVersion, "3.6.0") && ts.isGetAccessor(n)) {


Test patch:
diff --git a/baselines/reference/ts3.4/test.d.ts b/baselines/reference/ts3.4/test.d.ts
index f5a5937..127e736 100644
--- a/baselines/reference/ts3.4/test.d.ts
+++ b/baselines/reference/ts3.4/test.d.ts
@@ -50,3 +50,9 @@ type J = [
 ];
 import * as default_1 from "./src/test";
 export { default_1 as default };
+export declare type Asserts<T> = (val: unknown) => void;
+export declare const foo: {
+    bar: {
+        baz: <T>(val: unknown) => void;
+    };
+};
diff --git a/baselines/reference/ts3.5/test.d.ts b/baselines/reference/ts3.5/test.d.ts
index 4430e8b..bbdda3d 100644
--- a/baselines/reference/ts3.5/test.d.ts
+++ b/baselines/reference/ts3.5/test.d.ts
@@ -50,3 +50,9 @@ type J = [
 ];
 import * as default_1 from "./src/test";
 export { default_1 as default };
+export declare type Asserts<T> = (val: unknown) => void;
+export declare const foo: {
+    bar: {
+        baz: <T>(val: unknown) => void;
+    };
+};
diff --git a/baselines/reference/ts3.6/test.d.ts b/baselines/reference/ts3.6/test.d.ts
index a67db23..34d78b0 100644
--- a/baselines/reference/ts3.6/test.d.ts
+++ b/baselines/reference/ts3.6/test.d.ts
@@ -52,3 +52,9 @@ type J = [
 ];
 import * as default_1 from "./src/test";
 export { default_1 as default };
+export declare type Asserts<T> = (val: unknown) => void;
+export declare const foo: {
+    bar: {
+        baz: <T>(val: unknown) => void;
+    };
+};
diff --git a/baselines/reference/ts3.7/test.d.ts b/baselines/reference/ts3.7/test.d.ts
index 7c5a6ee..2644188 100644
--- a/baselines/reference/ts3.7/test.d.ts
+++ b/baselines/reference/ts3.7/test.d.ts
@@ -52,3 +52,9 @@ type J = [
 ];
 import * as default_1 from "./src/test";
 export { default_1 as default };
+export declare type Asserts<T> = (val: unknown) => asserts val is T;
+export declare const foo: {
+    bar: {
+        baz: <T>(val: unknown) => asserts val is T;
+    };
+};
diff --git a/baselines/reference/ts3.8/test.d.ts b/baselines/reference/ts3.8/test.d.ts
index 78a6446..6f13279 100644
--- a/baselines/reference/ts3.8/test.d.ts
+++ b/baselines/reference/ts3.8/test.d.ts
@@ -50,3 +50,9 @@ type J = [
     /*arr*/ ...boolean[]
 ];
 export * as default from "./src/test";
+export declare type Asserts<T> = (val: unknown) => asserts val is T;
+export declare const foo: {
+    bar: {
+        baz: <T>(val: unknown) => asserts val is T;
+    };
+};
diff --git a/baselines/reference/ts3.9/test.d.ts b/baselines/reference/ts3.9/test.d.ts
index 78a6446..6f13279 100644
--- a/baselines/reference/ts3.9/test.d.ts
+++ b/baselines/reference/ts3.9/test.d.ts
@@ -50,3 +50,9 @@ type J = [
     /*arr*/ ...boolean[]
 ];
 export * as default from "./src/test";
+export declare type Asserts<T> = (val: unknown) => asserts val is T;
+export declare const foo: {
+    bar: {
+        baz: <T>(val: unknown) => asserts val is T;
+    };
+};
diff --git a/baselines/reference/ts4.0/test.d.ts b/baselines/reference/ts4.0/test.d.ts
index a1ad540..1c8058d 100644
--- a/baselines/reference/ts4.0/test.d.ts
+++ b/baselines/reference/ts4.0/test.d.ts
@@ -50,3 +50,9 @@ type J = [
     ...arr: boolean[]
 ];
 export * as default from "./src/test";
+export declare type Asserts<T> = (val: unknown) => asserts val is T;
+export declare const foo: {
+    bar: {
+        baz: <T>(val: unknown) => asserts val is T;
+    };
+};
diff --git a/test/test.d.ts b/test/test.d.ts
index c332eec..5e2c9e9 100644
--- a/test/test.d.ts
+++ b/test/test.d.ts
@@ -53,3 +53,11 @@ declare function assert(val: any, msg?: string): asserts val;
 type J = [foo: string, bar: number, ...arr:boolean[]]
 
 export * as default from "./src/test";
+
+export declare type Asserts<T> = (val: unknown) => asserts val is T;
+
+export declare const foo: {
+    bar: {
+        baz: <T>(val: unknown) => asserts val is T;
+    };
+};