How to make Flow and Typescript work together in React? - reactjs

So, how to make Flow and Typescript work together in React? You will ask why you have both in the same project, but I am in the middle of the transition from Flow to Typescript, and for a brief period of time I would like to have them both.
The problem is, Flow reports an error for Typescript type definitions like this:
type person = {
name: string
surname: string
}
because Flow syntax is different:
type person = {
name: string,
surname: string,
}
I am using the VS Code and I can not find where (and how) to disable Flow to mark Typescript syntax as faulty and fail the compilation process. I tried everything: // #noflow, // $FlowFixMe but nothing can prevent reporting error on Typescript syntax.
Do you have any ideas?

Ok, I found the solution. In my case, I needed two lines on the top of the file:
/* eslint-disable prettier/prettier */
/* eslint-disable flowtype/no-types-missing-file-annotation */
This will do the trick.

Related

leaflet-radar + react : checkbox_div is not defined error

Note: Using React
I'm having trouble setting up a radar in my leaflet map object. I'm able to generate the map easily, but I get an error when I try adding a radar to the map.
The issue comes from this slice of code:
import RadarMap from 'leaflet-radar'
.
.
.
drawMap(){
let radar;
this.map = L.map(this.id);// eslint-disable-line
this.map.setView([this.latitude, this.longitude], this.zoom);
L.tileLayer("https://tile-{s}.openstreetmap.fr/hot/{z}/{x}/{y}.png", { // eslint-disable-line
accessToken: this.accessToken
}
).addTo(this.map);
radar = new L.Control.Radar({}); // eslint-disable-line
radar.addTo(this.map);
}
The error specifically occurs when I call this line:
radar.addTo(this.map);
If I don't call this line, my code will correctly generate a map. But this one line
breaks the map.
To be frank, I've been working on this error for hours now. I've altered this code zealously;
yet iteration after iteration, I still can't get this radar to work. If anyone knows how to help me with this problem, I'd be extremely grateful.
I figured out the problem.
Leaflet-radar was trying to use a global variable named checkbox_div. Since checkbox_div did not exist as a global variable, an error was raised. Adding checkbox_div as a global variable fixed the error.
I solved this error by using globalThis in the constructor of the element and using that to add a global variable.
constructor(props){
super(props);
globalThis.checkbox_div = undefined; // eslint-disable-line
}
In my solution, I gave checkbox_div the value of undefined, but I think it's possible to give checkbox_div any value. Just instantiating checkbox_div is the key.
An alternative solution would be to simply add checkbox_div in the .html file like this
<script>
var checkbox_div;
</script>

Unable to get type-safety (CustomTypeOptions) working with react-i18next

I recently successfully implemented using react-18next for localization needs inside my app. I have a small package that contains the localization files, react-i18next setup, and exports a class which is referenced in another application to get the i18n instance and pass it to the which wraps my components.
This has been deployed and works as expected.
I stumbled upon the documentation here (https://react.i18next.com/latest/typescript#create-a-declaration-file), which says that you are able to make the t function fully type safe. I would love to implement this, so that I am able to catch mis-matched key errors at compilation time, rather than needing to hunt for each case within the application.
I am having some trouble achieving this desired type-safety though, and wasnt sure if it was something that I am doing wrong or possibly a bug in the typing (I assume the former, as others seem to get the safety working without any issue).
Versions:
react-i18next “^11.15.6”
i18next “^21.6.14”
react “16.14.0”
typescript 4.1+
Repo structure (excluding package.json, tsconfig.json, etc) :
src
translations
translations_en.json
translations_es.json
MyTranslationManager.ts
react-i18next.d.ts
The translation files do not use any nested strings, and are separated by language (”_en” vs “_es”). Each language has all the needed strings in their localized format. The files are in this format:
{
"string1": "First string",
"string2": "Second string"
}
In my live (working) setup, this is how I initialize my instance:
import translationEN from "./translations/translations_en.json";
export class MyTranslationManager {
private readonly i18nInstance: i18nType;
constructor() {
this.i18nInstance = i18n.createInstance();
const defaultResources = {
en: { translation: { ...translationEN } },
};
this.language = "en";
this.i18nInstance
.use(initReactI18next)
.init({
resources: defaultResources,
lng: "en",
keySeparator: false, // we do not use nested translation resources
interpolation: {
escapeValue: false, // React already prevents XSS
},
});
}
// WORKING ON TYPE SAFETY
As directed in the docs, I create a react-i18next.d.s file to redeclare the “react-i18next” module - specifically the CustomTypeOptions interface:
import "react-i18next";
import translationEN from "./translations/translations_en.json";
declare module "react-i18next" {
interface CustomTypeOptions {
resources: typeof translationEN;
}
}
I do not declare a “defaultNS” option to CustomTypeOptions because I rely on the default namespace, “translation”.
When I attempt to compile the project with the above code, I get the following TS2344 issue:
node_modules/react-i18next/ts4.1/index.d.ts:203:25 - error TS2344:
Type 'string' does not satisfy the constraint 'Namespace<"btn_cancel" | "btn_save" | ... 86 more ... | "msg_unsavedChanges">'.
203 N extends Namespace = DefaultNamespace,
The error is thrown from each line in react-i18next/ts4.1/index.d.ts that attempts to set Namespace = DefaultNamespace.
I copied over as much of the code in index.d.ts as I could into the Typescript playground to try and get some insight into what is happening here, and I am able to get the compilation error to repro.
Hovering over the following items in the Typescript playground gives some interesting insight:
DefaultResources will resolve to { “btn_cancel”: string; “btn_ok”: string; }
DefaultNamespace will resolve to “ type DefaultNamespace<T = "translation"> = T extends "btn_cancel" | "btn_ok" ? T : string “
I assume this gets set by the use of the Fallback type, which gets passed in each key from DefaultResources via the keyof...
Link to playground.
My question is, why are the keys for the language files being set as the namespace? Is this by design? Am I importing the resources in an incorrect manner?
I noticed that the example here (https://github.com/i18next/react-i18next/blob/master/example/react-typescript4.1/no-namespaces/%40types/react-i18next/index.d.ts) only shows what the docs point to as an older version, i.e using the DefaultResources type instead of CustomTypeOptions. Any guidance on using the new method without namespaces would be greatly appreciated :)
For anyone working with i18next#v22.0.0 and react-i18next#v12.0.0, following the documentation here was successful for me (as of the time this was posted):
https://www.i18next.com/overview/typescript
I am now getting types for my translations inside of the t() function

How to include mxFloorplan.js in mxGraph inside React application using Typescript?

So I'm trying to create a simple react application to render a mxGraph that I'm loading from a file. I can load the model, but some shapes aren't rendering correctly. The problem is that they are a specific shape, that are part of the floorplan package, and I can't find a way to include those shapes in my code.
ps.: I'm new to working with mxGraph.
Things I tried
First thing I tried was downloading the mxFloorplan.js file into my application, and import it, like so:
// App.tsx
import './models/mxFloorplan'
const mx = factory({
mxBasePath: './models'
})
let graph: mxGraph
...
Because the docs on extending mxShape show that I should register a new shape: mxCellRenderer.registerShape('customShape', CustomShape); and the mxFloorplan.js file does that.
I then simply added this to the beggining of the file:
// mxFloorplan.js
import Graph, {
mxShape,
mxUtils,
mxCellRenderer,
mxPoint
} from 'mxgraph'
...
But then I get this error:
Then I thought that I needed mxCellRenderer to be linked to my graph instance? So I tried moving one of the shape definitions into App.jsx to test:
// App.jsx
const mx = factory({
mxBasePath: './models'
})
let graph: mxGraph
function mxFloorplanWall(bounds: any, fill: any, stroke: any, strokewidth: any)
{
mx.mxShape.call(this); <-- Error: "Expected 2 args, but got one"
this.bounds = bounds;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = (strokewidth != null) ? strokewidth : 1;
};
/**
* Extends mxShape.
*/
mx.mxUtils.extend(mxFloorplanWall, mxShape); <-- Error: "Property 'extend' does not exist on type mxUtils
// ... more code
mx.mxCellRenderer.registerShape(mxFloorplanWall.prototype.cst.WALL, mxFloorplanWall); <-- Error: mxFloorplanWall type not compatible with expected.
Really don't know how to solve these ones. On my research I only find references to
mxCellRenderer.registerShape('name', CustomShape), so not really sure on the rest.
How it looks
Here is how the diagram looks like (ignore the arrow and labels, please):
Here is what I'm actually rendering (the "black boxes" have shape=shape=mxgraph.floorplan.wallU):
As described in https://jgraph.github.io/mxgraph/docs/js-api/files/shape/mxShape-js.html, you must pass a constructor to mxCellRenderer.registerShape
function CustomShape() { }
CustomShape.prototype = new mxShape();
CustomShape.prototype.constructor = CustomShape;
// To register a custom shape in an existing graph instance,
// one must register the shape under a new name in the graph’s cell renderer
// as follows:
mxCellRenderer.registerShape('customShape', CustomShape);
}
I guess your issues come from a wrong port of drawio code (that use a very old Javscript syntax) and is not related to React at all. It is currently unclear to me what you are exactly have implemented. Here are some hints.
If you use TypeScript, the mxCellRenderer.registerShape signature is enforced by the mxgraph types https://github.com/typed-mxgraph/typed-mxgraph/blob/v0.0.5-0/view/mxCellRenderer.d.ts#L83.
When porting the mxFloorplanWall code to Typescript you should have a constructor like in the following (please avoid any!)
export class mxFloorplanWall extends mxShape { // or extends mx.mxShape depending how you manage mxgraph imports
public constructor(bounds: mxRectangle, fill: string, stroke: string, strokewidth: number) {
super(bounds, fill, stroke, strokewidth);
}
...
}
Calling super directly set the arguments in super class and avoid the errors
// mx.mxUtils.extend(mxFloorplanWall, mxShape); <-- Error: "Property 'extend' does not exist on type mxUtils
// avoid mx.mxShape.call(this); <-- Error: "Expected 2 args, but got one"
Same if you use Javascript, prefer the ES6 class syntax to declare the mxFloorplanWall class.

Maximum call stack size exceeded when using the new typescript enabled version of reactjs

I use the new typescript supported version of reactjs
along with the redux-orm and when u try to insert a value into the store i get this issue of "Maximum call stack size exceeded" the same works with the old template
Below is the code with new typescript supported reactjs which throws the error
https://reactjs.org/docs/static-type-checking.html#typescript and the old github version https://github.com/microsoft/TypeScript-React-Starter which works.
https://drive.google.com/open?id=15eolNjeYroyubgSmbGaaKfjxbe-IZ8KK
I am unable to understand what is different that causes the error with the new version. Thanks for any help.
Properties can't be defined directly on Model classes.
The root cause lies in the create-react-app's babel preset - transpilation output introduces additional property descriptors in Model prototype chain.
These properties interfere with descriptors installed by redux-orm during schema registration, resulting in Maximum call stack size exceeded error.
This can be avoided through declaration merging, specifically by providing a class and an interface with matching names. The interface contains Model properties, the class is almost 1:1 to JS Model definition.
Example:
interface Book {
id: number
title: string
}
class Book extends Model<typeof Book> {
static modelName = 'Book' as const
static fields = {
id: attr(),
title: attr()
}
}
I've created a repo with working example: https://github.com/tomasz-zablocki/redux-orm-ex-types-react-example
Mind you, these are custom types, but it's definitely where I'd like to take the #types/redux-orm package to, likely with the 0.14 release of redux-orm.

can we edit the definitely typed file in typescript to change some parameter types?

Can we edit definitely typed file in Typescript?
When using ui-grid with typescript I came across a scenario where I edited the
ui-grid.d.ts file to make the date filter work. I need to filter the date based on the displayed result in the ui-grid and not on the
raw data (the data which I am getting from the Web API).
Here is the code snippet:
ui-grid.d.ts file code:(under interface IFilterOptions)
condition?: number;
Corresponding typescript code:
column.filter = {
condition: (searchTerm, cellValue, row, column) => {
var date = this.$filter("date")(row.entity.Date, this.masks.date.angular)
return (date + '').toLowerCase().indexOf(searchTerm.toLowerCase().replace(/\\/g, "")) !== -1;
}
}
The error I faced is as follows:
Type '(searchTerm:any, cellValue:any, row:any, coloumn:any) => boolean' is not assignable to type 'number'
After that I made the changes to the filter object to return a number as follows:
column.filter = {
condition: (searchTerm, cellValue, row, column) => {
var date = this.$filter("date")(row.entity.Date, this.masks.date.angular)
var res: number = (date + '').toLowerCase().indexOf(searchTerm.toLowerCase().replace(/\\/g, "")) !== -1 ? 1 : 0;
return res;
}
}
But after this I got error saying that:
Type '(searchTerm:any, cellValue:any, row:any, coloumn:any) => number' is not assignable to type 'number'
After this I made the change in the definitely typed file i.e. in the ui-grid.d.ts file as follows:
under interface IFilterOptions
I changed
condition?: number;
to
condition?: (searchTerm: any, cellValue: any, row: any, column: any) => boolean | number;
so the corresponding filter function which worked for me is as follows:
column.filter = {
condition: (searchTerm, cellValue, row, column) => {
var date = this.$filter("date")(row.entity.Date, this.masks.date.angular)
return (date + '').toLowerCase().indexOf(searchTerm.toLowerCase().replace(/\\/g, "")) !== -1;
}
}
Is this the right way to solve this problem?
Can anyone guide me to the right solution if the above solution is not good or it is not a good practice to edit the definitely typed file?
And also used
column.filterCellFiltered = true;
instead of filter function but it didn't work. This is also a concern as why it didn't work because I need to filter the date based on the displayed result in the ui-grid and not on the raw data. Can anyone explain why it didn't work?
Please help me understand the right approach. Let me know if anyone require any other details. Thanks in advance.
Angular JS version: AngularJS v1.4.7
Angular JS definitely typed version : Angular JS 1.4+
ui-grid Version: * ui-grid - v3.0.5
ui-grid definitely typed version: ui-grid v3.0.3
typescript version: 1.0.3.0
i had also same problem ,
adding "< any >" beginning of the function should solve the problem.
like this :
condition: <any>((searchTerm, cellValue, row, column) =>
{
return cellValue.indexOf(searchTerm) > -1
})
and don't forget to parenthesis ().
You can, but the changes will be overwritten the next time you install/upgrade that dependency, and won't be reflected in git (assuming you're not checking generated files into source control). You're better off overriding the type definitions in your project. The common way to do this is within an #types directory but anywhere within your TS project will work.
You'll want to create a file with the extension .d.ts under TS's project files. The modules within this file will be merged with other declaration files, to determine the final type definition. So in your case you'd want:
// ui-grid.override.d.ts
declare module 'ui-grid' {
// overriden types go here
}
The benefit of this method is that you only need to add the types you want, and the rest will be merged with the definitely typed declarations.
This is a very useful tool if you need to do things like type globals, or to provide additional type information for libraries. It's used extensively in the definitely typed declarations for library plugins which alter an api in some way.
I'd recommend reading the TS docs on declaration files as they're an incredibly useful tool if used correctly.
Although if you do find the types in definitely typed are incorrect/incomplete then please create a PR for the benefit of everyone
I do not recommend to modify definitions and sources of the libraries you do not actively develop. What will happen when you will decide to upgrade to the newer version and it will override your changes? You will be forced to merge them each time you upgrade. And the larger your project will get the more complicated this will become.
I would recommend to either submit a request to the angular-ui team, or find a way to go with existing functionality.
Hope this helps.

Resources