Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Import non-js content as const string #42219

Open
5 tasks done
mariusGundersen opened this issue Jan 5, 2021 · 2 comments
Open
5 tasks done

[Feature] Import non-js content as const string #42219

mariusGundersen opened this issue Jan 5, 2021 · 2 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@mariusGundersen
Copy link

mariusGundersen commented Jan 5, 2021

Suggestion

There is a need for a way to import non-js content and process that content to produce TypeScript definitions, as asked for in for example #16607. But with the template literal types introduces in TS 4.1 I believe most of this can be solved without a plugin system. There are examples of projects that parse strings representing for example SQL, and produces useful types based on the string value. So given only the string content of a file it is possible to declare a module with useful types.

🔍 Search Terms

import module string

✅ Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

My proposal is something like this:

declare module "*.txt" {
  const content: import.meta.content; //this is the new feature
  export default content
}

(I'm using import.meta.content here as an example of how it could work. import.meta will contain many possible properties, so I'm just using content here as an idea)

This way the actual textual value of the file could be known both in the editor and at compile time. For example:

//given that example.txt contains 'example'
import text from 'example.txt';

type True = text extends 'example';

This isn't very useful in and of itself, but with template literal types it is now possible to parse and make use of other languages.

For example, when using css modules it is useful when the IDE can help and show all the classes in the css file. Here is a trivally simple (and therefore not completely working) example of how this can be done:

declare module "*.module.css" {
  const content: import.meta.content;

  // This is the magic that parses the css file and generates the css module object
  type ParseCSS<T extends string> = T extends `${string}.${infer ClassName} {${string}}${infer Rest}` 
    ? { [K in (ClassName | keyof ParseCSS<Rest>)]: string } 
    : {};

  export ParseCSS<content>;
}

(The code above can be tested here

Given a simple css file with classes this declaration will make it possible to import the file and use the classes in a project, like this:

import style from 'style.module.css';

export default (props: {value: string}) => <h1 className={style.title}>{props.value}</h1>;

This is just a simple example, there are many examples of parsing and working with strings that represent json and sql here. Something I've been looking into is parsing glsl files and extracting the list of uniforms and their types. I'm sure there are many other usecases for parsing the string into a type declaration.

So to summarize, by making the string content of a file available in a module declaration, existing features of TypeScript, like template literal types, makes it possible to parse the string and producing useful types.

@RyanCavanaugh RyanCavanaugh added Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript labels Jan 6, 2021
@mariusGundersen
Copy link
Author

I think with #42539 and the support for go-to-definition for text files then this feature would be a nice next step.

@nsaunders
Copy link

This is a great idea and I fully support it.

With that said, I'm focused on the CSS use case at the moment; and I've found that I can get by with essentially a *.css.ts module that just exports the CSS as a string. Some workarounds are certainly required, for example:

  • The build tool must extract the CSS content from the TypeScript module and output it to a *.css file, for example. (Webpack can do this very efficiently, but I'm not sure about others.)
  • Syntax highlighting usually doesn't work and must be recovered using e.g. VS Code's Inline HTML extension.
  • Prettier won't format the embedded CSS; but, hey, maybe they'll merge my PR someday.

Anyway, if interested, the relevant project is here: https://github.com/nsaunders/demitasse

Otherwise, thanks for creating the issue, and I look forward to this feature being added!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants