Repository navigation
Importing files other than TS modules #2709
Description
Activity
if you can use absolute path you can do this today by doing something like:
// Define a module
declare module "template.html!text" { var html: number; export default x; }
then your code would look like
import Html from "template.html!text"; // Html is a numberReacted by Omkara and Golden LightReacted by Andžej Maciusovič, Garry Filakhtov, Manuel Luciani, Roy Peled, Peter Berg, doomleika, ૮༼⚆︿⚆༽つ, Jeffrey Lanters, Philip Lysenko, Jason and 7 moreIt would be nice to not have to create manual declarations for every javascript module I want to import. I would think this keeps to the spirit of "Typescript is a superset of Javascript".
For example, I have an ES6 foo.js file sitting next to my bar.ts file. I'd love to just be able to:
import * as foo from 'foo.js'
and then have
foobe an implicitany.Reacted by Philipp Kretzschmar, Yago López, gianluca manenti, Alexander Trauzzi, Mikko Porkola, Cosmin Ababei, Christian Bundy, Aron Adler, John Rolf, Avindra Goolcharan and 31 moreThe problem is not the import, the problem is the type of your import (the type of
foo); with no information about the shape of the imported module the compiler has no way of helping you. we have talked about something like:import * as foo: IFoo from "foo";
Which would tell the compiler that you know shape of the module, and optionally you can pass
anyto just load the module with no checking.I actually tried something like that just as guess when I was playing around with it :)
The issue I think I'd still have is that I couldn't just take a bunch of es6 javascript files and one by one convert them to typescript without breaking everything. I love the fact that I used to be able to take a
.jsfile, change the suffix to.ts, run it through the compiler and it would work.I wonder if there could be a compiler flag like the
impilictyAnyoption, something likeallowImplicitAnyImportsthat would tell the compiler to only pull type information from the import if it is available. If you want to be strict about imports and/or use the explicit typing syntax you described, you could turn it tofalse.Reacted by Ashwin Hegde, Yago López, Sun, Aron Adler, reggaeguitar, Ben Jackman, Sergei Sergeev, William Rummler, Alexander Nazarov, Slava and 9 moreUsing TypeScript 1.5-beta, transpiling to ES6.
import { Foo } from 'foo'; export class Bar { constructor() { new Foo(); } }The above code complains:
Cannot find external module 'foo'.
However, the following JavaScript is generated:
import { Foo } from 'foo'; export class Bar { constructor() { new Foo(); } }As far as static type checking goes, Foo is considered to be "any" so you can also call it as a function, use it in arithmatic, etc.
Interestingly, when building with gulp-typescript I don't get the error but atom-typescript does give me the error. I'm guessing there is a compiler option that controls this, but I am not sure what it is (which is why I am here).
Zoltu (@Zoltu) please see my comment in #3019 (comment) to answer your question..
However, the following JavaScript is generated:
TypeScript errors do not block emit. it tells you the compiler did not understand some aspects of your code, but syntactic transformations still take place.
As far as static type checking goes, Foo is considered to be "any" so you can also call it as a function, use it in arithmatic, etc.
You need to tell the compiler the shape of the thing you are importing. currently the only way to do that is to write a .d.ts file e.g.:
declare module "foo" { export class Foo{ } }
Reacted by Huan Li and Decebal Dobrica- addedIn DiscussionNot yet reached consensusNot yet reached consensus
on May 4, 2015 I'm coming to this as a newcomer, having only recently started playing with TypeScript as part of the Angular 2 developer preview. I presume there's going to be plenty more people who follow a similar path, so let me capture my impressions:
I appreciate the value of typing, but it's not my primary motivation for using TypeScript. I'm more interested in decorators and the fact that its the recommended language for Angular 2. My expectation was that typing would be an optional addition that I could gradually apply, but not that I'd have to immediately find or create type definitions for all my code and its dependencies.
Whatever the reason, throwing errors on valid JavaScript code is confusing when TypeScript is explicitly described as a superset of JavaScript. The first thing many people will do is load up an existing app and try to compile it. Getting a bunch of errors in response doesn't give a great first impression.
That "Cannot find external module" error is really bad. At first I thought it meant the compiler couldn't find the file on disk, so I spent quite a while moving it around and trying to figure out what was wrong. I also thought that it meant the compiler hadn't output anything. Compiler errors that don't prevent compilation are rather odd. Shouldn't these be warnings, or at least the compiler should make it clear that they haven't prevented code emission?
I have a large, existing Angular 1 application, organised into a few hundred ES6 modules. Eventually I want to migrate it Angular 2, and thus probably TypeScript, but this is going to have to be a gradual process. Having the compiler throw hundreds of errors because my code lacks types isn't going to make this much fun.
Reacted by Kushagra Sharma, nino-porcino, Asif Mehedi, Mendel Kramer, Alex, Alex Leung, Emiliano Parizzi, John Jones, Patrick Mowrer, Ondrej Slinták and 75 moreReacted by Ashwin Hegde, Ahmed, Yago López, Cosmin Ababei, Christian Bundy, Aron Adler, Qiao Anran, reggaeguitar, William Rummler, Christian Muñoz and 11 moreJon Rimmer (@jonrimmer) This is good feedback. Would be curious to here what your preferred workflow would've been.
As far as the module errors go, I totally agree they're pretty bad and very painful to debug.
As for the superset/errors part, what behavior would you prefer? Keep in mind the errors you're seeing are more like warnings in most languages, they can be ignored and JS is still emitted (were you using VS or some other editor?). Then you can fix up those errors over time. Some of them are to satisfy the compiler, some might be actual bugs in your code. The hope is that you can grab an existing .d.ts from DefinitelyTyped for much of your library code and fix any errors related to common code. We also have some ideas for ways to ease this process further (ex #2916).
If we didn't give those errors (ex some compiler flag like --noTypeErrors) then what would really be the point in starting to write with TypeScript? It'd be identical to your JavaScript except with an additional compile step in your workflow. Eventually you'd have to turn off the --noTypeErrors flag and be back in this state with many errors due to lack of type information. If you only got errors on the code you explicitly annotated then you'd actually have to write way more type annotations than necessary to get the type checking we advertise as powerful and useful.
Dan Quirk (@danquirk) I am using Visual Studio Code. I can live with the current behaviour, but I wish the compiler's messaging was clearer. Something like "Warning: No registered type information for external module foo — using implicit 'any' type." If you have to keep calling them errors, some message making it clear that code is still being emitted would be helpful. Mohamed Hegazy (@mhegazy)'s suggestion of being able to add an explicit type, even if it's
any, to the import to shut up the compiler would be nice as well.As for using TypeScript with untyped code, I actually get a lot. First, I get all the other ES6 and ES7 features you guys have implemented. In particular, I get to use Angular 2's annotations, which require decorator support. If you compare the TS vs ES5 examples in the Angular 2 documentation you can see that the ES5 equivalent code isn't nice, whereas the TS version is pretty awesome. That alone would be enough to make me use TS for my Angular 2 code, regardless of typing.
Also, even if my existing codebase and some of its dependencies aren't typed, by using TS for compilation, I can write all my new code with types, and gradually add them to the old code. I can also consume the core Angular 2 libraries in their original TS form, and get intellisense and checking on my use of them, at least.
Finally, I think maybe there's a question of project philosophy to consider here. It seems like until recently TypeScript existed in a niche where it existed to provide JavaScript + Types to people who wanted them, and could afford to be somewhat uncompromising in how it applied that vision. But its recent enhancements have turned it into more of a general ES.next compiler along the lines of Babel, and maybe that requires a reconsideration of how hard it pushes typing, vs. making interop with untyped code as painless as possible. I'm optimistic that types will make it into JS proper eventually. But with the best will in the world, there is going to be more untyped JS code around than not for a long time to come.
Reacted by Asif Mehedi, Ioannis Kokkinidis, Chen Zhutian, Huan Li, Ashwin Hegde, arthexis, Yago López, Christian Bundy, reggaeguitar, William Rummler and 4 moreBut what do you expect to happen with your untyped code? Do you want some way to turn off all type checking for a file? I get that the migration initially involves a lot of type errors but what do you envision instead? Even with file level settings as soon as you want to add type annotations to one function in that file you need to deal with the many errors from that file.
The entire purpose of emitting in the face of these type errors is to acknowledge how much untyped code is out there. Then the migration process to TypeScript can happen piecemeal without having broken your entire application until you've dealt with every single type error.
TypeScript is definitely aiming to add value in the form of ES6/7/etc features before they're in every browser/engine. But the fundamental point of the project is types (hence the name :)). There have always been type-less transpilers and will continue to be. What parts of the migration process are particularly painful to you with the .d.ts on DefinitelyTyped and if #2916 existed to easily get .d.ts for your JSDoc'd code? (I assume a bunch of code without JSDocs would be one).
Reacted by Ilia CholyI seem to recall at one of Anders talks at Build 2015, he again referenced how any valid javascript file was a valid typescript file. I'd vote for, again, having a compiler switch similar to allowing implicit anys. If typescript can find a type for a module import, use it, else use "any". If people want to be strict, they can set it appropriately. For cases where you are starting new with Typescript, you can set the flag to strict, and then for external, untyped modules, use some sort of language construct (see Mohamed Hegazy (@mhegazy) idea above) to explicitly set the import type to "any". For existing code bases, you can set the compiler to allow implicit any imports.
I really love Typescript, it's a wonderful, powerful tool. I think it's adoption has been so high in part because it's so flexible (both in the optional typing and it's cross platform behavior). It plays nice with the existing Javascript ecosystem. The current module implementation unfortunately does not.
Reacted by Tom Esterez, Max Lynch, Ashwin Hegde, Tom Piarulli, andy, Bradley Ayers, Aron Adler, David Price, William Rummler, Manuel Luciani and 4 moreReacted by Tom Esterez, Ashwin Hegde, William Rummler and Manuel Luciani- addedNeeds ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.This issue needs a plan that clarifies the finer details of how it could be implemented.and removedIn DiscussionNot yet reached consensusNot yet reached consensus
on May 19, 2015 72 remaining items
Is there anything special I have to do to reference the .d.ts file so that my imports work? I can't seem to get the solutions listed here to work.
// webpack.d.ts import {IUseableStyle} from './common/IUseableStyle'; declare module '*.html' { var _: string; export default _; } declare module '*.scss' { var _: IUseableStyle; export default _; }
// component.ts import template from './component.html'; // [ts] cannot find module './component.html';
tsconfig.json looks like:
{ "compilerOptions": { "emitDecoratorMetadata": true, "experimentalDecorators": true, "moduleResolution": "node", "noImplicitAny": true, "outDir": ".tmp/src/", "allowJs": true, "target": "es6", "allowUnreachableCode": true }, "include": [ "/src/**/*" ] }Your .d.ts is a module (i.e. it has a top level
importorexport), modules have their own scope. this makes all declaration in this file not visible outside it. your file should look like:declare module '*.html' { var _: string; export default _; } declare module '*.scss' { import {IUseableStyle} from './common/IUseableStyle'; var _: IUseableStyle; export default _; }
Wildcard is not working for me , maybe it's due to I use typescript 1.8.
This doesn't work:declare module '*.html' { var _: string; export default _; }
The following works fine:
import "text!Components/Templates/MyTemplate.html"; ... var template = require('text!Components/Templates/MyTemplate.html');
Maksim Shamihulau (@bomzj) Wildcard only works in TS 2.0 or higher.
Reacted by Aluan Haddad and Alex FilatovEDIT: never mind. It seems that the README for the svg-inline-loader plugin is wrong. You need to use
'svg-inline-loader'as the loader name.// webpack.config.js config.module.loaders.push({ test: /\.svg$/, loader: 'svg-inline-loader' });
I've tried to follow through this issue but I'm a bit lost and would appreciate some help.
I'm trying to load a SVG file into my .ts file, so I can use it in my HTML template (Angular 2) as an inline SVG. This allows me to change the colour of the SVG with CSS. I'm using web pack 1.x.
This is what I've tried:
// webpack.config.js config.module.loaders.push({ test: /\.svg$/, loader: 'svg-inline'. // Installed locally with `npm install svg-inline-loader` });
// declarations.d.ts declare function require(string): any; declare module "*.svg" { const content: any; export default content; }
// Tried both this: import damSvg from '../../../assets/icon/barrier-types/dam.svg'; // And this: const damSvg = require('../../../assets/icon/barrier-types/dam.svg');
In both cases, I get a webpack 'Cannot find module' error.
Can anybody shed any light on what I'm doing wrong?
aluanhaddad commented
on Mar 29, 2017 ContributorMore actionsYou either have the wrong path or you haven't listed .svg as a resolvable extension.
resolve: ['.svg', '.ts']
Your question would probably be better asked on stack overflow. it also has nothing to do with TypeScript , being about Webpack loading neither TypeScript nor JavaScript files
Reacted by Licínio OliveiraAluan Haddad (@aluanhaddad) thank you for taking the time to respond. It ended up being an error with the loader I was using. I've updated my post above.
aluanhaddad commented
on Mar 30, 2017 ContributorMore actionsI didn't realize your issue was resolved (but I'm glad to hear it). I guess I'm used to seeing edits in bold.
Is there a way to import a file, raw as is, as a string, using Typescript purely?
I dont want to involve SystemJS, webpack or rollup to solve this problem.
Reacted by byeval and Sebastián GurinTypeScript does not provide run-time functionality. If emitted TypeScript runs under NodeJS this functionality is already there. There are other libraries that provide similar functionality in the browser.
Reacted by Aluan HaddadAvindra Goolcharan (@avindra)
Did you get any solution for your problem. I am also trying to import markdown(.md) files in typescript without using webpack and other module.I have written in typing.d.ts
declare module *!txt* { const value: any; export default value; }in TS file
import * as readme from "./README.md!txt"; // I am getting error for this.Kitson Kelly (@kitsonk) could you suggest library which can be used to import non-code module in typescript.
Nothing worked for me, until I've changed my import to the
* as <x>format.This works with TS 2.4.1:
declare module '*.pegjs' { var _: string; export default _; }Then:
import * as cypher from './grammar/cypher.pegjs'And the relevant parts of webpack config:
var config = { resolve: { extensions: [ '.ts', '.js', '.pegjs' ], }, module: { rules: [{ test: /\.pegjs$/, use: 'raw-loader', }] }, } module.exports = config;Reacted by Jakub Beránek, Oleg Morozenkov, Charl, Mark Macdonald, ScottCybak, Jean Alexander Woldner and mmis1000Reacted by Justin Gaba and limaofengI tried this:
declare module "mirage-server" import MirageServer, { Factory } from 'mirage-server';
but get:
error TS2665: Invalid module name in augmentation. Module 'mirage-server' resolves to an untyped module at '/Users/nikos/WebstormProjects/client/node_modules/mirage-server/lib/index.js', which cannot be augmented.
Nikos (@quantuminformation) You can't put the
declare moduleline in the same file as the imports, it's got to go into a.d.tsfile.Reacted by Dmitry A. Efimenko and Lennart Hildebrandt- locked and limited conversation to collaborators
on Jul 18, 2018
I've successfully been using SystemJS and TypeScript for a while now. I've been about to use the CommonJS syntax to easily import other TS modules, as well as other resources:
This is made possible by simply declaring the following function:
I'm now trying to do the same with the new ES6 syntax:
Of course I can do the same as before and declare and use 'require', but it'd be nice to keep it consistent. Perhaps assume that if an exclamation mark is in the path, then don't assume it's a TypeScript import?