In Typescript is there a way to restrict / limit an exported function so it can only be imported by certain files?
Asked Answered
H

2

13

I want developers to use a class / interface instead of importing functions directly.

Is there a way to limit so only the class can import the function?

I don't want to have to put all the functions in a single file as it's not scalable in a large project

i.e. I don't want to use this pattern:

// myclass.ts

// no exports on the functions
function foo(){ ... }
function bar(){ ... }

export class MyClass {
 Foo(){ return foo() }
 Bar(){ return bar() }
}

What I'm trying to achieve:

// foo.ts
export function foo(){ ... } 
// I want this to be private but it needs to be exported so the class below can use it

// bar.ts
export function bar() { ... }

// myclass.ts
import { foo } from 'foo';
import { bar } from 'bar';

export class MyClass {
 Foo(){ return foo() }
 Bar(){ return bar() }
}

// anyotherfile.ts
import { foo } from 'foo' // Stop from importing directly
import { MyClass } from 'myclass' // use this instead
Hyo answered 4/1, 2021 at 5:3 Comment(4)
To my knowledge once they're exported they're exported. Why not put foo and bar in the myclass.ts instead of in different files?Ravishing
@Ravishing That's how it is currently structured (which may be the best solution). The two issues I was trying to solve by splitting out everything into individual files: 1. files don't become thousands of lines in length. 2. Less versioning conflicts when multiple developers are making changes to a single giant file.Hyo
IMHO, this is a problem for convention to solve, not the type system. Call the file my-class-foo.ts, and put it in a directory with the class. That gives a pretty good clue that importing that file directly is never what you want, unless you are in a file that concerns itself with actually implementing MyClass.Howes
Great question @Tom. When building an internal app framework, for instance, that we want to expose just as "fw" but it is coded as many classes and functions in lots of files. I don't want the need to precompile it and put it all inside a single file. I want the freedom to evolve its code as my app also evolves. A import forced clause would be very handful to allow to import not explicit exported functions.Funkhouser
E
1

I'm assuming you're creating something that's meant to be installed as an npm package and that not everything in your project is just source-code dependencies.

If this is not your case then I suspect its likely impossible to achieve what you would like without magic. Typescript, as far as I know, has no notion of 'package level' exports as you would have in Java for example.

Ensure that the entry point to your library/package points to index.js

Let say you have the following structure: module/ functions/ MyClass.ts index.ts

//a.ts
export function a(): any // export this from files inside functions/

Then your class works as you wanted it to

//MyClass.ts
import { a } from './functions/a'
 
export class MyClass {
    a(): any {
         return a()
    }
}

Finally, to restrict access from outside the module to only the class, export only the class in the module's index file

//index.ts
export * from './MyClass'

Now anyone installing your package will not be able to import anything except MyClass from '@yourpackage-name'

Note however, they can always brute force an

import from @yourpackage-name/build/src/functions/a

Hope this helps.

Edyth answered 5/1 at 8:58 Comment(2)
This is pointless. You are not even attempting to restrict access to those functions. You described the workaround for those protections as requiring "brute force", but actually an IDE will auto write that without the developer even needing to think how to import the function.Abuttal
That highly depends on how your IDE is configured. You can configure both VS Code and WebStorm to prefer directory imports. As both of our replies state, there is no language native way to do package-level exports. Clearly, both answers relay heavily on external tooling to aid the developer.Edyth
A
0

With TypeScript it is kind of possible to restrict imports.

You are talking about developers using your classes, so I am assuming you are distributing this as a npm package, which usually means you have a build step.

In your build step you can replace the function declarations in .d.ts files with something like this:

export const foo: never

That way the devs would get a TypeScript error if they tried to use the functions you wanted to protect.
Sure they can simply do // @ts-ignore to get around this, but they will at least know they are not using your lib in the intended way.

Altering files in the build step may not be easy to configure, so as an alternative you could simply exclude the .d.ts files from the build for your "hidden" scripts.
The devs wont get an error if they try to import them, but the lack of types should make it obvious to them that they are not using the correct API.


The only way to split your code into multiple files and be sure that devs wont be importing functions that you don't want them to use is to bundle the scripts into one file as a part of your build.

Some npm packages already bundle their code like this as a way to reduce package size and improve build time for devs.

Abuttal answered 30/12, 2023 at 0:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.