Package foo
has many useful TypeScript interfaces that I want exposed transitively through package bar
to consumers (represented as package baz
), but I cannot find an elegant way to re-export that full set of types (namespace?) for downstream use. foo
is a frequently changing dependency which I do not strictly maintain. It's important that its interfaces automatically reflect through bar
, as bar
is the sole provider of foo
to baz
.
Consider the following package dependency chain:
foo -> bar -> baz
Now consider some basic implementations:
// pkg foo
export interface Fooz { x: number }
// pkg bar
import * as foo from 'foo';
// Objective: get all interfaces/types re-exported through this package
export type FooMod = import('foo');
// ^ This would be ideal, but not supported
// Module 'foo' does not refer to a type, but is used as a type here. Did you mean 'typeof import('foo')'?ts(1340)
// pkg baz
import * as bar from 'bar';
// This is my end customer's package. How can they get to interfaces from `foo`, hosted by `bar`?
// e.g. observe the return type:
const doStuffWithBar = (): bar.FooMod.Fooz => {
//
}
Things I've tried so far:
export FooMod = typeof foo;
. typeof foo
creates a new type, and is lossy. It may bring over types from all entities physically present in the module, but types/interfaces from the foo
module are all dropped. This is not adequate.export FooMod = import('foo')
. This produces a TS error, mentioned inline in comments.Without a solution, I have to force my customers to actually install the foo
module to access its top-level types. I could also inline exports in bar
for all types in foo
, but that's not sustainable, and given the size and change rate of foo
, the worst outcome.
Is such a solution feasible?
Use export * (as X)? from 'package'
in Bar. If you want to import the types directly in Baz, skip the as <X>
, otherwise you can import the namespace in Baz like the example below:
Foo
// index.ts
export interface Test {
a: string
}
Bar
// index.ts
export type * as Foo from 'foo';
Baz
import { Foo } from 'bar';
let a: Foo.Test;
Bar
// index.ts
export type * from 'foo';
Baz
import { Test } from 'bar';
Edit: As noted by OP's comment, even with export types
the non-type exports in Foo will also show up when importing in Baz. But they can neither be used in Baz, as typescript will give the error: <variable> cannot be used as a value because it was exported using 'export type'.
and it doesn't even look like they're really exported from Bar
, only in name in the declrataion file.