I have a project I am working on where we are creating standalone javascript files that will get injected into a web page to execute a command. Each script is injected at runtime and called as though it is part of a function. So for instance one file might be a command to run a search on google where the command will first select the input field, then set the value, then click the submit button, etc.. These scripts do a variety of things each unique to the page they are going to be injected into.
Each script generally returns a boolean to indicate if the script worked successfully or not. The scripts are written in javascript, but I am looking to improve the readability of these scripts as they can become quite large and would like to move to typescript.
I have currently been exploring using esbuild to compile each typescript file and generate a corresponding javascript file. While this has worked with mostly no issues, I am struggling with how a typescript file can have a return statement without the compiler saying, A 'return' statement can only be used within a function body.ts(1108)
A simple example typescript file could be:
const input document.querySelector('someSelector');
input.value = "someValue";
return true;
When injected into a page it is done like this:
const scriptToInject = loadScript('someScript');
const globalVars = {};
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
const func = new AsyncFunction(globalVars, codeToRun);
const codeResult = await func(globalVars );
I have a project I am working on where we are creating standalone javascript files that will get injected into a web page to execute a command. Each script is injected at runtime and called as though it is part of a function. So for instance one file might be a command to run a search on google where the command will first select the input field, then set the value, then click the submit button, etc.. These scripts do a variety of things each unique to the page they are going to be injected into.
Each script generally returns a boolean to indicate if the script worked successfully or not. The scripts are written in javascript, but I am looking to improve the readability of these scripts as they can become quite large and would like to move to typescript.
I have currently been exploring using esbuild to compile each typescript file and generate a corresponding javascript file. While this has worked with mostly no issues, I am struggling with how a typescript file can have a return statement without the compiler saying, A 'return' statement can only be used within a function body.ts(1108)
A simple example typescript file could be:
const input document.querySelector('someSelector');
input.value = "someValue";
return true;
When injected into a page it is done like this:
const scriptToInject = loadScript('someScript');
const globalVars = {};
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
const func = new AsyncFunction(globalVars, codeToRun);
const codeResult = await func(globalVars );
Share
Improve this question
asked Mar 29 at 17:08
starsoccerstarsoccer
375 bronze badges
7
|
Show 2 more comments
2 Answers
Reset to default -2Here you go
<script type="module">
import initSwc, {
transformSync,
} from 'https://cdn.jsdelivr/npm/@swc/[email protected]/wasm.js';
await initSwc();
let ts = `interface Person {
name: string;
age: number;
}
function greet(person: Person) {
return "Hello, " + person.name + "!";
}
export { greet };`
let {
greet
} = await import(
`data:text/javascript,${
transformSync(ts, {}).code
}`
);
console.log(greet({
name: 'X'
}));
</script>
I have currently been exploring using esbuild to compile each typescript file and generate a corresponding javascript file.
Overkill.
node
, deno
, and bun
can all convert TypeScript syntax to JavaScript, without deliberately using third-party libraries.
In the case of Node.js, the Amaro module is used, which in turn depends on SWC, which ultimately just strips TypeScript syntax from the file.
I am struggling with how a typescript file can have a return statement without the compiler saying, A 'return' statement can only be used within a function body.ts(1108)
Depends. Deno and Bun may or may not use Microsoft TypeScript's tsc
, or might not; might do "type checking" or might not, depending on the case. Becuase in general, tsc
is slower than other options. You'll have to read various issues to see this discussion amnong Node.js and Deno maintainers for yourself. Bun does not use tsc
at all. Bun uses it's own TypeScript parser.
You can customize "type checking" in Deno.
E.g., deno.json
{
"nodeModulesDir": "auto",
"lint": {
"rules": {
"tags": ["recommended"],
"include": [
"no-irregular-whitespace",
"constructor-super",
"eqeqeq",
"no-async-promise-executor",
"no-await-in-sync-fn",
"no-case-declarations",
"no-global-assign no-node-globals",
"no-non-null-asserted-optional-chain",
"no-process-globals",
"no-unreachable",
"no-unsafe-negation",
"no-unused-labels",
"no-unused-vars",
"no-undef"
],
"exclude": [
"no-explicit-any",
"no-undef"
]
}
},
"compilerOptions": {
"target": "esnext",
"types": [
"https://raw.githubusercontent/microsoft/TypeScript/2ac4cb78d6930302eb0a55d07f154a2b0597ae32/src/lib/es2024.arraybuffer.d.ts"
],
"lib": [
"dom",
"dom.iterable",
"dom.asynciterable",
"deno.ns",
"deno.unstable"
]
}
}
Not in Node.js or Bun.
In some instances, depending on the tsc
being used, it can be far behind browser implementations.
For example, resizable ArrayBuffer
was shipped in node
, deno
, bun
- and the browser - months before Microsoft TypeScript officially supported resizable ArrayBuffer
.
If you just want to convert Microsoft TypeScript syntax to JavaScript I would not even bother with type checking.
Here's how to strip Microsoft TypeScript types using node
, deno
, and bun
Strip TypeScript types in Node.js, Deno, and Bun
Node.js
node --no-warnings node-strip-types.js https://raw.githubusercontent/user/repo/refs/heads/main/file.ts transform
node --no-warnings node-strip-types.js ../path/to/file.ts transform
// https://github/nodejs/node/commit/53b1050e6f692ee0330e1076e045b58aada0032d#diff-4e8f3cce79719e4a337f58575b20c998b093eb64164b847ca0eb9ba884d8a801R338
// node --no-warnings node-strip-types.js https://raw.githubusercontent/user/repo/refs/heads/main/file.ts transform
// node --no-warnings node-strip-types.js ../path/to/file.ts transform
import { stripTypeScriptTypes } from "node:module";
import { readFileSync, writeFileSync } from "node:fs";
import { argv, stdout } from "node:process";
let [
,
,
sourceTs,
mode = "transform",
sourceUrl = sourceTs,
sourceMap = false,
] = argv;
sourceMap = Boolean(sourceMap);
let url = new URL(sourceTs, import.meta.url);
let code;
if (url.protocol === "file:") {
code = readFileSync(url, "utf8");
} else if (url.protocol.startsWith("http")) {
code = await (await fetch(url)).text();
}
const strippedCode = stripTypeScriptTypes(code, { mode, sourceUrl, sourceMap });
stdout.write(strippedCode);
Deno
deno install --entrypoint ../path/to/file.ts
// Transpile TypeScript to JavaScript using Deno built-ins
// Usage: deno -A deno-ts-js-cache.js path/to/file.ts
// Write Deno's generated cache .ts.js file to stdout and current directory
// ts: Path to .ts script
const [ts] = Deno.args;
const url = new URL(import.meta.resolve(ts));
const { pathname } = url;
const filename = pathname.split("/").at(-1);
const decoder = new TextDecoder();
// Path to generated cache .ts.js script
const jsCache = `file${pathname}.js`;
// info: Get Deno cache and TypeScript cache subdirectories
const info = new Deno.Command(Deno.execPath(), {
args: [
"info",
"--json",
],
});
// Deno cache directory and generated TypeScript subdirectory
const { denoDir, typescriptCache } = JSON.parse(
decoder.decode((await info.output()).stdout),
);
// Cache
// https://docs.deno/runtime/fundamentals/modules/#vendoring-remote-modules
const command = await new Deno.Command(Deno.execPath(), {
args: ["install", "--entrypoint", "-r", ts],
}).output();
// Generated cache .ts.js file
const js = (await Deno.readTextFile(`${typescriptCache}/${jsCache}`))
.replace(/\/\/#\ssourceMappingURL=.+\n\/\/.+$/img, "");
console.log(js);
await Deno.writeTextFile(`${filename}.js`, js);
Deno.exit(0);
deno -A deno-ts-js-cache.js ../path/to/file.ts
Bun
bun build ~/path/to/file.ts --no-bundle --outfile=file.ts.js
// @ts-ignore
? You can try to ignore thereturn
statement. – jabaa Commented Mar 29 at 17:26return
statement or only some of them? – jabaa Commented Mar 29 at 20:28