#`import type` without producing an ES module?

96 messages · Page 1 of 1 (latest)

west veldt
#

We're trying to write a script to run standalone in a web browser, inside a script tag, and it's not a module.

However, there are some globals that are made available by other scripts, that we want to have typechecked by TypeScript.

Right now, we're using import type, specifically importing the type, then using declare const ... to declare the presence of the global in the surrounding environment.

However, using import type at all seems to cause TSC to conclude that our standalone script that only accesses global variables is somehow an ES module. It then randomly adds stuff to our script that crashes it at runtime and prevents it from working.

TSC emits Object.defineProperty(exports, "__esModule", { value: true });, but exports does not exist. Because the script is not a dang module. And we can't find any way to turn this off, or any alternative to import type that allows us to properly include the type definitions for the globals that already exist, that we're not importing because this is 100% not a module.

Is there any way to include these type definitions without becoming a module, or a way to stop TSC from emitting code that literally crashes when we run the code standalone and not in a module? Because it's not a module, and it shouldn't be a module.

type="module" on the script tag is an okay workaround, but we're upset with TypeScript deciding that our code is a module in the first place, because it's not. It's literally not a module and we really need TSC to see that. How?

crisp minnow
#

can’t you import them in an ambient declaration?

#

and augment globalThis in that ambient declaration

#

The thing is as soon as you use an import statement TS sees your file as a module so you have to avoid that in the script itself

crisp minnow
#

just to illustrate better what I mean, just create a file called for instance global.d.ts somewhere in your source folder where it will be picked up by TS, add the following contents:

import { Foo } from ‘foopkg’

declare global {
  const foo: Foo
}
 export {}
#

and you should have that var available in your script without needing an import statement

west veldt
west veldt
# crisp minnow just to illustrate better what I mean, just create a file called for instance gl...

It looks like this works for making the global variable available, but I can't figure out how to make the types available under a namespace. Right now we use this:```ts
// @ts-ignore
import type * as ort from 'onnxruntime-common'

declare const ort: typeof import('onnxruntime-common')which is hacky for reasons (including needing an `@ts-ignore`) but *with the `import type` we can then use types such as `ort.TypedTensor`* and with the `global.d.ts` approach I can't figure out how to do it. Here is the `global.d.ts`:ts
declare global {
const ort: typeof import('onnxruntime-common')
}

export * as ort from 'onnxruntime-common'```but it still requires import { ort } from './global' in order to use the ort namespace which is the nono

west veldt
#

ugh. We are going through terrible pain again finding out that TypeScript conveniently disallows every single thing that could possibly allow this.```ts
declare global {
const ort: typeof import('onnxruntime-common')
export * as ort from 'onnxruntime-common'
}

export {}"Exports and export assignments are not permitted in module augmentations". why? because TSC hates us, of course! why else would it intentionally disallow every possible solution?ts
declare global {
const ort: typeof import('onnxruntime-common')
import * as ort from 'onnxruntime-common'
}

export {}obviously nopets
import * as ort_ from 'onnxruntime-common'

declare global {
export import ort = ort_
}

export {}
nope!ts
declare global {
namespace ort {
export * from 'onnxruntime-common'
}
}

export {}not even closets
declare global {
namespace ort {
import * from 'onnxruntime-common'
}
}

export {}syntax error!ts

declare global {
const ort: typeof import('onnxruntime-common')

type ort = import('onnxruntime-common')

}

export {}
sadhasfkjsgahfjkdgdsts
import * as ort_ from 'onnxruntime-common'

declare global {
const ort: typeof import('onnxruntime-common')

namespace ort = load the stupid package 'onnxruntime-common'

}

export {}

#
declare global {
    const ort: typeof import('onnxruntime-common')
}

export namespace ort {
    export * from 'onnxruntime-common'
}
```nopeeee

TypeScript has a dedicated error for each and every one of these telling us that the exact thing we're trying to do is disallowed because apparently "screw you that's why"
#

there's no possible way it's supposed to be this hard. everyone must have simultaneously screwed up in unison to accidentally create the world's most hostile compiler for making actual scripts that are loaded on a webpage after other scripts

#

how am I supposed to import types if trying to import types causes my script to turn into a "module" and TSC will generate code that causes it to crash? absolutely no idea

#

the solution, of course, is to go back to the stone age. teaching sand to think was a mistake.

#

we're going to go punch a wall or something. ugh

west veldt
#

Okay, it looks like we have a partial solution if we redeclare every single type we use:```ts
declare global {
const ort: typeof import('onnxruntime-common')

namespace ort {
    type InferenceSession = import('onnxruntime-common').InferenceSession
    type TypedTensor<T> = import('onnxruntime-common').TypedTensor<T>
}

}

export {}```This is... okay I guess, but... annoying

crisp minnow
#

Another approach could be to use reference syntax, which is actually kinda deprecated outside specific situations but

#
/// <reference types="onnxruntime-common" />

<all types in onnxruntime should be globally available here>
west veldt
crisp minnow
#

I meant inside the script file itself

west veldt
#

when I call ort.InferenceSession.create(...) I want an ort.InferenceSession, not just InferenceSession

#

is there any way to do that with a reference?

crisp minnow
#

I think I may have found a solution for you in the meantime

#

A better one than those references

#

lemme check if it works

west veldt
#

yeah?

#

alright~

crisp minnow
#

Yes works

#

Ok going back to those ambient files

#

just make ort.d.ts

#

put in it:

export * from 'onnxruntime-common'
export as namespace ort
#

profit

#

(you can delete the global.d.ts of course)

#

ah but wait, could it be that that doesn't export ort.TypedTensor ?

west veldt
crisp minnow
#

I see ort.InferenceSession

west veldt
#

I'll try it out when I'm busy making sure my IDE settings sync works properly

crisp minnow
#

Yes it puts all the exports of your ambient module in a global namespace

west veldt
#

I hate how terribly typescript is documented, there is no reference, only a bunch of stupid tutorials

#

if this does what we think it does .... right after we are done configuring the stupid settings sync here we'll try this

crisp minnow
#

The strange thing is I'm not seeing all of the exports

#

ugh

#

I think it also didn't export the types

#

only the values

west veldt
#

!resolved

crisp minnow
#

Are you sure?

west veldt
#

just having that in an ort.d.ts and nothing else

#

thank you so much~

crisp minnow
#

yw in that case 😄

west veldt
#

that's what we have been looking for this entire time we're so upset that it was so difficult to find

#

this should be documented this should be documented

#

it is documented in the most ridiculous way as a footnote in some pages that have nothing to do with this

crisp minnow
#

I also didn't know about it tbh

#

I went to look in lodash's DefinitelyTyped source

west veldt
#

wooow

crisp minnow
#

To see what they do

west veldt
#

yeah and since ambient modules are just auto-imported regular modules ...

#

I can sorta see how that happened but it's insane that it took that

#

this should be documented

crisp minnow
#

Yes I agree

#

I'm curious how it comes that I'm not getting all the types though, maybe it's my tsconfig

west veldt
#

that's so terrible

crisp minnow
#

Hey there's some templates 😄

west veldt
#

it's so terrible that we might have to find where the stupid docs are and make a pull request because it's actually outrageous

#

one second

crisp minnow
#

That's the section

#

But yeah

#

hard to find if you don't know what you're looking for

west veldt
crisp minnow
#

Ah right didn't see it was in there

west veldt
#

it was a google search for all occurrences of "export as module" across the entire docs website

#

and there are only like 3 hits, only one of which even mentions the thing in prose

#

we might PR to edit this section https://github.com/microsoft/TypeScript-Website/blob/78b88c3c6cf5ee3d2287f43dec4f720f11a85ef4/packages/documentation/copy/en/reference/Modules.md#ambient-modules to mention ambient modules that use export as namespace to represent something like other script files in a browser

GitHub

The Website and web infrastructure for learning TypeScript - TypeScript-Website/Modules.md at 78b88c3c6cf5ee3d2287f43dec4f720f11a85ef4 · microsoft/TypeScript-Website

#

because that's where we would look

crisp minnow
#

Myeah maybe

west veldt
#

oh great that's the page you just linked

#

I guess we'll just improve the UMD modules section if we can

crisp minnow
#

Heh

#

It can also be used as a global variable, but only inside of a script. (A script is a file with no imports or exports.)

#

it's right there 😄

west veldt
#

it's not, because the package published to npm is not a UMD module, so I ignored that section. I'm going to try to make something that can be skimmed by someone who has been suffering for over two hours straight, i.e. not reading every single word of every page because they're having a panic attack

#

anyway, to PR, no need to chat any more, thank you

crisp minnow
#

I'm sorry, didn't mean to offend you. I agree discovery is kind of terrible in the TS docs.

west veldt
#

you didn't really offend me but I really did not want to explain exactly why "containing some form of correct information via a technicality" is not a substitute for "being discoverable for this use case"

#

having "export as namespace is good for UMD modules" and "these modules can be accessed through a global variable" is cool but we were looking for "having an ambient module that re-exports an existing package under a global namespace" and it never registered that export as namespace could redirect re-exports as well because it's Literally Never Stated

#

not to mention that we didn't even try re-exports in the first place because we thought having them at the top level would be useless, so it absolutely wasn't on our mind to have anything involving those

#

but anyway yeah done with that lol

crisp minnow
#

makes sense

#

anyway, glad I could help you

west veldt
#

thank you~