Typescript newbie, first project. I carefully read the handbook, but fail to solve a simple problem. I have an internal module :
module MDVault1Encoding {
export function encode(store:Store, pwHash: Buffer): string {
(...)
return (...);
}
export function decode(encoded:string, pwHash: Buffer): Store {
(...)
return (...);
}
}
Then I have client code outside this module that calls these functions, like in an instance method :
this.store = MDVault1Encoding.decode(container.data, this.pwHash);
When the module definition and the client code live in the same .ts file, all goes well.
But when I put the module into an md_vault_1_encoding.ts file, and the client code in fileio.ts, adding a /// <reference path="./md_vault_1_encoding.ts" /> in the latter's header, things go wrong.
md_vault_1_encoding.ts compiles neatly, but fileio.ts yields this :
$ tsc fileio.ts
fileio.ts(39,26): error TS2304: Cannot find name 'MDVault1Encoding'.
fileio.ts(48,19): error TS2304: Cannot find name 'MDVault1Encoding'.
What am I doing wrong ?
Somewhere else in md_vault_1_encoding.ts you have a top-level import or export declaration.
This turns your file into a module (AKA "external module") and means your file doesn't put any properties in the global namespace.
You can either remove that import / export declaration (probably not possible), or you can add an export modifier to your namespace (export module MDVault1Encoding { ...) and then in fileio.ts write
import { MDVault1Encoding } from './md_vault_1_encoding';
Related
I cannot give too much information here (because there really isn't), but only this:
All of the sudden, after adding a #Method function to a stencil component:
#Method()
async setMenuItems(items: Element[]): Promise<void> {
// code here
}
the component stopped compiling with the following - really unhelpful - error:
[ ERROR ] ./src/components/menu-content/menu-content.tsx:63:44
build error
L62: #Method()
L63: async setMenuItems(elements: Element[]): Promise<void> {
L64: const unsupportedChildren = elements.filter(e => !this.isSupportedChild(e)).map(e => e.tagName);
[12:37.1] build failed in 7.02 s
Things to notice
the return type Promise<void> inside the error-message is highlighted red
there are other #Methods that do work within this component (even with the same return type).
the "broken" #Method is structurally equal to those that do work.
TypeScript compiler does not complain about anything
Only stencil compiler fails
I already tried...
to google for this issue - did not find any hints to this problem
to remove the async and add return Promise.resolve()
to rename the method (I mean.. why not)
to move the method to another place in class
to remove the whole method (compiles fine x( )
to remove the #Method decorator (compiled, but of course my method is removed from API)
to delete node_modules folder and reinstall
I remember that I already had this error once, and apparently I somehow fixed it (or not, idk). But if I did, I cannot remember how.
Does anyone have an idea how to debug this - or even better fix?
I figured it out. A more complete version of my component is:
import { Element, ... } from '#stencil/core';
class MenuContent {
#Element() element: MenuContentElement;
#Method()
setMenuItems(elements: Element[]): Promise<void> {
// ------------------^^^^^^^
// Element is meant to be the built-in browser interface for Element
// but stencil thinks that this is the imported Element from '#stencil/core'!
}
}
The exact problem here is, that the stencil-compiler seems to assume that the elements parameter is of type Element that is imported from #stencil/core which is obviously wrong and leads to this strange unhelpful error.
Possible Solutions
1. Use an alias type for the built-in Element type
// types.ts
export type DomElement = Element;
// menu-content.tsx
import { DomElement } from './types';
...
async setMenuItems(elements: DomElement[]): Promise<void> { ... }
2. Switch to HTMLElement
Note: This is only legit, when you don't need to support other Element-types such as SVGElements for example!
async setMenuItems(elements: HTMLElement[]): Promise<void> { ... }
3. Use alias in import statement
Please note: When using #stencil eslint rules, they will complain about your renamed import and say that "own class members are not allowed to be public".
I created a ticket for it here: https://github.com/ionic-team/stencil-eslint/issues/28
import { Element as ElementDecorator} from '#stencil/core';
class MenuContent {
// eslint will complain about that:
// "Own class properties cannot be public."
#ElementDecorator() element: HTMLMenuContentElement;
}
I experienced this same issue not with the Element type but with the Event type, so it appears to be rooted deeper - also about a year after you reported this issue it seems to still be a problem with Stencil
My Problem:I'm struggling with something that I would have thought would be quite simple: I have a react-native project where I'm using react-apollo, flow and flow-typed, and am running into an issue satisfying flow with the way I'm using the withApollo HOC. The flow error I'm getting is:
Missing type annotation for TProps. TProps is a type parameter declared in function type [1] and was implicitly
instantiated at call of withApollo [2].
My question: I'm wondering how I should pass TProps to withApollo... what is the correct/best way to do this?
Background:
In my file, I have the proptypes for my component declared:
type type ListCollaboratorsProps = {
...
};
I use ListCollaboratorsProps when creating my component:
class ListCollaborators extends React.Component<ListCollaboratorsProps, ListCollaboratorsState> {
and I export my component after wrapping it in withAPollo:
export default withApollo(ListCollaborators);
After seeing the flow error, I have tried the following:
export default withApollo<ListCollaboratorsProps>(MyApolloComponent);
which seems to make flow happy... but then I get this error when trying to run my app in the simulator:
Can't find variable: ListCollaboratorsProps
which I'm confused about, since I can use ListCollaboratorsProps just fine when declaring my component...
I want to write something like this inside my src/core/Chessman.js file:
import King from './chessmen/King'
class Chessman {
static factory(side, quality) {
switch(quality) {
case 'king' : return new King(side) break
// ... other qualities
}
constructor(side) { this.side = side }
cast(position, ref) { }
run(position, startRef, endRef) {}
}
and inside my src/core/chessmen/King.js file:
import Chessman from '../Chessman'
class King extends Chessman {
constructor(side) {
super(side)
this.iterative = false // true for Queens, Rooks and Bishop
this.directions = [
'up', 'up+right', 'right', 'right+down',
'down', 'down+left', 'left', 'left+top'
]
}
// overrides parent behavior
cast(position, ref) {}
run(position, startRef, endRef) {}
}
But sadly I get the error (while testing) with Karma, jasmine and babel
TypeError: Super expression must either be null or a function, not undefined
at src/core/chessmen/King.js:57
And there's no line 57 for the moment in King.js !
You have a circular dependency error. Given what you've shown us, consider the following steps:
Chessman.js starts loading
It pauses execution so its dependencies can load.
King.js starts loading since it is a dependency.
King.js throws because class King extends Chessman runs, but Chessman has not been set yet, because it paused on step #2
You'd be much better off moving your factory function to its own file, to avoid cyclical dependencies. The only safe circular dependencies in JS are ones that are not needed when the module itself is initialized. Since class extends X runs at module initialization time, it is not safe for cycles.
If this was literally your only class, you could write your app such that King.js was imported before Chessman.js, but given your usage of a factory, and your naming scheme, I assume there are other chess pieces. Since every single chess piece class will trigger this issue, there is no way to import them in the correct order. Avoiding the issue by moving the factory function out of Chessman.js is the only solution to this.
If you want to have a factory, instead of saving it directly in the base class module, move it to it's own module - chessman.factory.js. There, do whatever Chessman.factory does in a method or something. This way the chessman.js module wouldn't have to know about modules that need itself,
I am trying to refactor some test code and in two packages I need to do the same thing (connect to a DB). I am getting an import cycle. I get why I can't do it, but am wondering what the best way around it is.
Some specifics, I have three packages: testutils, client, engine.
In engine I define an interface & implementation (both exported).
package engine
type interface QueryEngine {
// ...
}
type struct MagicEngine {
// ...
}
And then in the testutils package I will create a MagicEngine and try and return it.
package testutils
func CreateAndConnect() (*engine.MagicEngine, error) {
// ....
}
Now in the test code (using a TestMain) I need to do something like
package engine
func TestMain(m *testing.M) {
e, err := testutils.CreateAndConnect()
// ....
os.Exit(m.Run())
}
This is of course a cycle. I want to do this so that I can in the client package also use this testutils.CreateAndConnect() method. I don't want to repeat the code in both packages. I don't want it in the main code of the engine package, it is very specific to the tests.
I tried adding it as an exported method on the engine test class (engine/engine_test.go) and using it in the client/client_test.go. No dice. :/
I feel I have done this in other languages, but could be crazy. What is the best way to structure this code for reusability?
You could use black-box style testing because the components of engine are exported. Change your tests to be in package engine_test:
package engine_test
import "engine"
import "testutils"
func TestMain(m *testing.M) {
e, err := testutils.CreateAndConnect()
// ....
os.Exit(m.Run())
}
I'm doing an experiment with wxWebConnect test application, incorporating the xpcom tutorial at "http://nerdlife.net/building-a-c-xpcom-component-in-windows/"
I adapt MyComponent class as necessary to compile together with testapp.exe (not as separate dll), and on MyApp::OnInit I have the following lines:
ns_smartptr<nsIComponentRegistrar> comp_reg;
res = NS_GetComponentRegistrar(&comp_reg.p);
if (NS_FAILED(res))
return false;
ns_smartptr<nsIFactory> prompt_factory;
CreateMyComponentFactory(&prompt_factory.p);
nsCID prompt_cid = MYCOMPONENT_CID;
res = comp_reg->RegisterFactory(prompt_cid,
"MyComponent",
"#mozilla.org/mycomp;1",
prompt_factory);
Those lines are copied from GeckoEngine::Init(), using the same mechanism to register PromptService, etc. The code compiles well and testapp.exe is running as expected.
I put javascript test as below :
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
const cid = "#mozilla.org/mycomp;1";
obj = Components.classes[cid].createInstance();
alert(typeof obj);
// bind the instance we just created to our interface
alert(Components.interfaces.nsIMyComponent);
obj = obj.QueryInterface(Components.interfaces.nsIMyComponent);
} catch (err) {
alert(err);
return;
}
and get the following exception:
Could not convert JavaScript argument arg 0 [nsISupport.QueryInterface]
The first alert says "object", so the line
Components.classes[cid].createInstance()
is returning the created instance.
The second alert says "undefined", so the interface nsIMyComponent is not recognized by XULRunner.
How to dynamically registering nsIMyComponent interface in wxWebConnect environment ?
Thx
I'm not sure what is happening here. The first thing I would check is that your component is scriptable (I assume it is, since the demo you copy from is). The next thing I would check is whether you can instantiate other, standard XULRunner components and get their interface (try something like "alert('Components.interfaces.nsIFile');" - at least in my version of wxWebConnect this shows an alert box with string "nsIFile".
Also, I think it would be worth checking the Error Console to make sure there are no errors or warnings reported. A magic string to do that (in Javascript) is:
window.open('chrome://global/content/console.xul', '', 'chrome,dialog=no,toolbar,resizable');