Create a typescript definition file for a 3rd party node module (react-signature-canvas) - reactjs

I'll use React-Signature-Canvas as the example.
the react-signature-canvas node module install looks like this in my project dir:
react-signature-canvas
build
index.js
src
bezier.js
index.js
point.js
LICENSE
package.json
README.md
The index.js file looks has the following signature:
export default class SignatureCanvas extends Component {
This looks pretty straight forward. I figured I would just create an index.d.ts in the module's root dir, and get it working, then figure out a better place to store it in my project later (i.e., outside of node_modules, with is in gitignore).
But I can't seem to get it to work. My typings file looks like this:'
declare module 'react-signature-canvas'
{
interface ISignatureCanvasProps
{
velocityFilterWeight?: number;
minWidth?: number;
maxWidth?: number;
dotSize?: number;
penColor?: string;
backgroundColor?: string;
onEnd?: () => void;
onBegin?: () => void;
canvasProps?: any;
}
class SignatureCanvas extends React.Component<ISignatureCanvasProps, any>
{
}
export = SignatureCanvas;
}
I am I am trying to use the Signature Pad like this:
import * as React from 'react';
import SignatureCanvas = require('react-signature-canvas');
export class DeliverySignature extends React.Component<any, undefined>
{
public render(): JSX.Element
{
return (
<div>
<h4>Signature</h4>
<SignatureCanvas
canvasProps={{width: 500, height: 200}} />
</div>
);
}
}
Everything compiles fine, and Webpack seems happy. But when I go to load the page, I get
Uncaught (in promise) TypeError: Cannot read property 'replaceChild'
of null
at Function.replaceChildWithTree (DOMLazyTree.js:69)
at Object.dangerouslyReplaceNodeWithMarkup (Danger.js:41)
at Object.dangerouslyReplaceNodeWithMarkup [as replaceNodeWithMarkup] (DOMChildrenOperations.js:124)
at ReactCompositeComponentWrapper._replaceNodeWithMarkup (ReactCompositeComponent.js:784)
at ReactCompositeComponentWrapper._updateRenderedComponent (ReactCompositeComponent.js:774)
at ReactCompositeComponentWrapper._performComponentUpdate (ReactCompositeComponent.js:724)
at ReactCompositeComponentWrapper.updateComponent (ReactCompositeComponent.js:645)
at ReactCompositeComponentWrapper.performUpdateIfNecessary (ReactCompositeComponent.js:561)
at Object.performUpdateIfNecessary (ReactReconciler.js:157)
at runBatchedUpdates (ReactUpdates.js:150)
What am I missing here? I am assuming I have imported incorrectly.
Thanks.

TypeScript has nothing to do with your error. The declaration file purpose is to help the compiler help you, but your code can run without them.
Nevertheless, your declaration file is incorrect. It's not supposed to contain any implementation. {} is also a kind of implementation. Consider this question in order to fix that. But again, this is not the source of your error.
Also, the naming convention is filename.d.ts, not .dt.ts
It seems like you are importing correctly. You can change it to:
import * as SignatureCanvas from 'react-signature-canvas';
But it's the same thing, except for the later one is ES6-compliant.

As you can see in this pull request, types for react-signature-canvas were added to DefinitelyTyped library.
You can add it to your project by executing following commands:
yarn add #types/react-signature-canvas
OR (using NPM)
npm i #types/react-signature-canvas.

Related

How do I import jStat in a Svelte project

I have a Typescript file in a Svelte project and would like use jStat https://github.com/jstat/jstat like the following:
export namespace Statistics
{
export function cdfNormal (x:number, mean:number = 0, standard_deviation:number = 1)
{
return jStat.normal.cdf(x,mean,standard_deviation);
}
};
I installed it via npm install --save jstat
I tried
import _ from "jstat";
and
var { jStat } = require('jstat')
But both didn't work.
The package says:
Currently jStat is exposed as j$ and jStat inside an object, rather than exported directly. This may confuse some module loaders, however should be easily remedied with the correct configuration.
But just calling jStat doesn't work either. What am I doing wrong?
The package should be imported as:
import jStat from 'jstat';
All the functions (e.g. mean) will be on the this default export object. The import has to be in the file using it.
The package supplies no types and no third party types (#types/jstat) seem to exist. You can type the module manually to any degree you like. E.g. add a file jstat.d.ts like this:
declare module 'jstat' {
const jStat: {
mean: (arr: number[]) => number;
// ...
};
export default jStat;
}
Or just declare it any if you do not mind the lack of type safety.

create-react-app with typescript - how to put types in separate file

I'm using CRA with typescript (create-react-app myapp --typescript)
I have some typescript stuff in my App.tsx that I would like to store externally, and I've tried creating App.d.ts, index.d.ts, module.d.ts and none of it works.
Here's the interface I'm using:
declare interface IArgs {
home: string,
away: string
}
What do I need to do to be able to declare all my Typescript stuff in a file that my source files can share?
Put in external file eg. interfaces/interfaces.ts:
export interface IArgs {
home: string,
away: string
}
Then in App.tsx where you want to use it you import it by: import { IArgs } from 'interfaces/interfaces'; and use it for your needs.

Importing Typescript classes into React-scripts - is not a constructor

I have an existing app and I'm trying to import a Typescript file, I use Yarn and React-scripts.
Module not found: Can't resolve './DiamondNodeModel'
import {DiamondNodeModel} from './DiamondNodeModel'
In DiamondNodeModel.ts
export class DiamondNodeModel extends NodeModel {
constructor() {
super("diamond");
this.addPort(new DiamondPortModel("top"));
this.addPort(new DiamondPortModel("left"));
this.addPort(new DiamondPortModel("bottom"));
this.addPort(new DiamondPortModel("right"));
}
}
I'm assuming I'm missing something that allows importing TypeScript files.. but I'm not sure where to set that with React-scripts..
EDIT
Changing the extension finds it, but it still can't compile
WEBPACK_IMPORTED_MODULE_3__DiamondNodeModel_ts.DiamondNodeModel is not a constructor
We managed to solve this problem by adding:
export { DiamondNodeModel }
at the end of the DiamondNodeModel.ts file.

TypeError: __webpack_require__.i(...) is not a function

I am getting a webpack TypeError when I am trying to simplify an import. The following code works without any issues. Here I am importing a React Higher-Order-Component (HOC) called smartForm from core/components/form/index.js.
core/components/form/index.js (does a named export of smartForm)
export smartForm from './smart-form';
login-form.jsx (imports and uses smartForm)
import { smartForm } from 'core/components/form';
class LoginForm extends React.Component {
...
}
export default smartForm(LoginForm);
However, I want to simplify the import to just import { smartForm } from 'core'. So I re-exported smart-form in core/index.js and imported it from core. See the code below:
core/index.js (does a named export of smartForm)
export { smartForm } from './components/form';
// export smartForm from './components/form'; <--- Also tried this
login-form.jsx (imports and uses smartForm)
import { smartForm } from 'core';
class LoginForm extends React.Component {
...
}
export default smartForm(LoginForm); // <--- Runtime exception here
This code compiles without any issues, but I am getting the following runtime exception at the line export default smartForm(LoginForm);:
login-form.jsx:83 Uncaught TypeError: webpack_require.i(...) is not a function(…)
What am I missing?
P.S. Here are the Bable and plugin versions that I am using:
"babel-core": "^6.18.2",
"babel-preset-es2015-webpack": "^6.4.3",
"babel-preset-react": "^6.16.0",
"babel-preset-stage-1": "^6.16.0",
tl;dr
For the questioner: Add this to your webpack.config.js:
resolve: {
alias: {
core: path.join(__dirname, 'core'),
},
},
For the general audience: Make sure the thing you try to import is indeed exists in that package.
Explanation
Questioner's problem: importing own code like npm modules
You try to import your module's exports in the same fashion how you import something from an npm package from the node_modules folder: import { something } from 'packagename';. The problem with this is that doesn't work out of the box. The Node.js docs give the answer on why:
Without a leading '/', './', or '../' to indicate a file, the module must either be a core module or is loaded from a node_modules folder.
So you either has to do what Waldo Jeffers and Spain Train suggested and write import { smartForm } from './core', or you can configure webpack so it can resolve your import path via its aliases which are created to solve this exact problem.
Debugging the error message in general
This error can arise if you try to import something from an existing npm package (in node_modules) but the imported thing doesn't exist in the exports. In this case, make sure there were no typos and that the given thing you try to import is indeed in that package. Nowadays it is trendy to break libraries into multiple npm packages, you might be trying to import from a wrong package.
So if you get something like this:
TypeError: __webpack_require__.i(...) is not a function
at /home/user/code/test/index.js:165080:81
at Layer.handle [as handle_request] (/home/user/code/test/index.js:49645:5)
To get more information on what import you should check, just open the output file generated by webpack and go to the line marked by the topmost line in the error stack (165080 in this case). You should see something like: __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_9_react_router_dom__["match"]). This tells us that there is no match export (or there is but it isn't a function) in react-router-dom, so we need to check our stuff around that import.
Since core is a folder of your app and not an npm module, Webpack can not understand which file you want to load. You must use a correct path pointing to a file. You have to replace import { smartForm } from 'core'; by import { smartForm } from './core/index.js
This error will occur by many reasons. Once I encountered this error when I add js in file-loader then when I removed it start to work correctly.
{
test: /\.(ttf|eot|svg|gif|jpg|png|js)(\?[\s\S]+)?$/,
use: 'file-loader'
},
When I remove |js it works
{
test: /\.(ttf|eot|svg|gif|jpg|png)(\?[\s\S]+)?$/,
use: 'file-loader'
},
Just remove these 2 line from config
const context = resolve.alias.context('./', true, /\.spec\.ts$/); context.keys().map(context);

How should I include an external .js file in my Angular 2 project?

I am using Angular 2's TypeScript API with webpack to create a browser app. Unfortunately one of my components requires the use of functions in an external .js file from the App Engine Channel API.
Unlike my other .js dependencies I don't think I can precompile this .js file in my webpack bundle because I believe it is dynamically generated.
What's the most appropriate way to load the file into my app and use it? How can I avoid async loading issues?
To extend on what Mark already pointed out:
Yes, you can indeed just load them in the head section of your HTML file above where you load your bundle/Angular 2 project.
And in the component, where you want to use that code you could just write the declaration of the goog variable above your Component class:
declare var goog: any;
And inside your component you can now use all the methods you want, just without auto-completion.
If you want auto-completion you could install the TypeScript definition files via npm: https://www.npmjs.com/package/#types/gae.channel.api
Or just place it in your typings folder right away and reference it at the top of your component file with:
/// <reference path="../typings/gae.channel.api.d.ts" />
gae.channel.api.d.ts:
// Type definitions for GoogleAppEngine's Channel API
// Project: https://developers.google.com/appengine/docs/java/channel/javascript
// Definitions by: vvakame <https://github.com/vvakame>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
declare namespace goog.appengine {
export class Channel {
constructor(token: string);
open(handler?: Function): Socket;
}
export class Socket {
close(): void;
onopen: () => void;
onmessage: (message: any) => void;
onerror: Function;
onclose: () => void;
}
}
Its kind of primitive but you can just place your js files in your html file above where you load your bundle.

Resources