When using deno to write applications or tools, it is desirable to execute those directly as binary [argv], rather than deno path/to/binary.ts [argv].
It could be possible to build custom versions of deno with code embedded, but I won't cover that here (see #986).
In this issue I'm looking at using deno as an executable interpreter with a shebang, such as this file binary containing:
#!/usr/bin/env deno
import { main } from "../src/main";
main();
This currently does not work, for two separate reasons:
binary rather than binary.ts), deno will not load it.Ultimately this means that it doesn't seem like you can do this with deno directly, rather you need something like a wrapper shell script or binary around invoking deno.
Ignoring the shebang line seems entirely reasonable, as that is not valid JavaScript | TypeScript in the first place.
I'm not sure what would be an acceptable solution regarding the extension.
Node just interprets files without an extension as .js files.
I would assume that deno would use TypeScript for extensionless file names.
But I'm not really sure what about extensions in file names with a shebang line.
Relying on the file name in this particular case is tricky because it's often the case that an executable may be symlinked or renamed during installation. It's common in Node today with scripts installed with npm.
I don't want file extensions in my /usr/local/bin but if the file happens to be script.js that needs to be parsed as JS and not TS then script.js cannot be installed to /usr/bin as just "script".
The solutions I see are all ugly - maybe someone else has some better ideas.
Works well for #!/usr/local/bin/deno --js but for #!/usr/bin/env deno you need hacks like this that I once needed to use feature flags in node:
#!/bin/sh
":" //#; exec /usr/bin/env node --harmony-proxies "$0" "$@"
#!/usr/bin/env deno
// deno-language: js
or something like that. I don't like it really but being optional for cases when there is no file extension that would at least make it possible to write scripts to be installed as system commands.
#!/usr/bin/env deno
// ... ts code here
and
#!/usr/bin/env denojs
// ... js code here
This is the last one that I thought about and doesn't seem that bad. But it would mean either installing two binaries or one binary and a symlink.
All of the above have some issues, meybe someone has a better idea.
All JS currently passes through the TypeScript compiler currently, which is likely to persist, especially if we end up supporting type checking of JS via JSDocs. I do not think treating the vast majority of extensionless files as TypeScript though would create any userland problems, as the compiler is in a very loose mode, and any JavaScript that would be invalid TypeScript is probably a bad idea anyways. It would be best to treat it as TypeScript and then only deal with it if it actually causes problems we can't solve.
@kitsonk I don't think it's that simple. Even this trivial example:
let x = 1;
x = 'a';
console.log(x);
passes as JS but not as TS - both in Deno itself - see:

Update:
I know that in theory TS is syntactically a superset of JS, but even though all JS code can in principle be parsed as TS, it doesn't necessarily mean that it doesn't violate the type system.
To make it work we would need to use any as the type for all variables that are not explicitly typed instead of using the type inference that is used everywhere else, and we would need to do it for all TS code if we want any JS code to be parsed as TS with no type errors.
As for me, I'd rather go the other way and compile the TS code with --strict by default (with a --loose switch in deno instead of non-strict by default) but that's just me and I know it will probably be non-strict by default (with hopefully a short switch like -s for strict parsing) but I hope Deno will not be even less strict than the default non-strict tsc mode, by switching off the type inference.
@rsp there are a few issues here that then get all coupled together that should be solved before we try to solve JavaScript support for shebang:
(A couple of them are things that have been talked about but I realised didn't have issues)
My opinion is that we could/should implement shebang support for TypeScript only and then deliver the right solution for JavaScript as an incremental change.
Perhaps "how should deno handle extensionless files" should be a separate issue from "deno should ignore shebangs"?
Most helpful comment
Perhaps "how should deno handle extensionless files" should be a separate issue from "deno should ignore shebangs"?