4

I'm not sure what changed, maybe it is even related to babel, but I started getting errors like UserControler_1 is undefined when I use things like this

UserControler.ts

export function signOut() { console.log("Sign Out") }

Page.tsx

import * as React from "react;
import { signOut } from "./UserControler";
import { TouchableWithoutFeedback, Text } from "react-native";

class Page extends React.Component {
  _signOut = () => signOut()

  render() {
    return (
      <TouchableWithoutFeedback onPress={this._signOut}>
         <Text>Sign Out</Text>
      </TouchableWithoutFeedback>
    )
  }
}

Above results in error like this

UserControler_1 is undefined

Sometimes it errors more specifically i.e.

Can't find variable: signOut

Weirdest thing is that if I change code to something like this, it works fine

import * as React from "react;
import { signOut } from "./UserControler";

class Page extends React.Component {    
  render() {
    return (
     <TouchableWithoutFeedback onPress={() => signOut}>
       <Text>Sign Out</Text>
     </TouchableWithoutFeedback>
    )
  }
}

Very confused here

My tsconfig

{
  "compilerOptions": {
    "moduleResolution": "node",
    "module": "es6",
    "target": "es6",
    "lib": ["es7"],
    "allowJs": true,
    "checkJs": true,
    "jsx": "react-native",
    "removeComments": true,
    "outDir": "./dist",
    "typeRoots": ["node_modules/@types", "./typings"],
    "noFallthroughCasesInSwitch": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "allowSyntheticDefaultImports": true,
    "strict": true
  },
  "exclude": ["./node_modules", "./android", "./ios", "./__tests__", "./dist", "./__mocks__"],
  "include": ["./src"]
}

This builds into dist folder from where babel draws its files and hence makes application work, my babelrc

{
  "presets": ["react-native"]
}
Ilja
  • 44,142
  • 92
  • 275
  • 498
  • the reason for the second code working (the button) is that you are assigning `signOut [undefined]` to `onClick` which means it does nothing. in the first example, you are executing `signOut()` which means it gives an error, since `signOut` doesn't exist. This is not an answer to your problem, just the reason why one bugs out, and two doesn't :-) – DoXicK Feb 13 '18 at 15:05
  • @DoXicK updated examples to be consistent, thing is that second version also executes `signOut` as expected – Ilja Feb 13 '18 at 15:08
  • and it is the exact same path ? – DoXicK Feb 13 '18 at 15:10
  • @DoXicK exact same import yeh – Ilja Feb 13 '18 at 15:11
  • then it probably is a circular reference somewhere. I've had this before where file A loads B, B loads C, C loads A. Which meant that the export from A in C were not exposed yet as you imported C. – DoXicK Feb 13 '18 at 15:16
  • Which means: Version 1: class gets built and references a function that is not initialized yet during "compile/parse time". Version 2: the function reference is used in "run-time", at which point it is resolved – DoXicK Feb 13 '18 at 15:18
  • I observe similar strange bugs on a typescript/react-native project. They are irritating, but go away upon restarting react-native and typescript. They seem some form of cache / race condition between ts compiler and rn bundler. May be wrong about it but it seems they started to happen after upgrading to ts 2.7.x. Are they persistent in your case - like first compiling and then bundling still produces those bugs? – artur grzesiak Feb 13 '18 at 19:26
  • Note: You are importing `React` incorrectly. Use `--esModuleInterop` and _always_, without exception `import React from 'react';` – Aluan Haddad Feb 13 '18 at 19:57
  • @arturgrzesiak I think mine started at 2.7 as well, and yeh I'm experiencing same behaviour as you, it works fine until I do a live reload / refresh of the app, after this I have to re-build it, its supper annoying. – Ilja Feb 14 '18 at 09:38
  • @AluanHaddad Thanks for advice I will update my project, but not sure if this is whats causing it. – Ilja Feb 14 '18 at 09:39
  • @AluanHaddad do I have to use it alongside `module: "commonjs"` ? Otherwise (with my ts config mentioned above) I get errors about React in vscode. Edit: actually if I use it like that it screams errors in my project, I assume vscode wasn't updated yet – Ilja Feb 14 '18 at 11:29
  • @Ilja no TypeScript 2.7 – Aluan Haddad Feb 14 '18 at 11:59
  • have you tried adding _**.bind(this)**_ like this: (`onPress={() => signOut}.bind(this)`) – flix Feb 15 '18 at 12:08
  • `import * as React from "react;` missed the closing double-quote – Karen Grigoryan Feb 18 '18 at 08:11

2 Answers2

1
<TouchableWithoutFeedback onPress={() => signOut}>

Works because you are returning the reference to signOut, the function you imported above. The important thing to note is that => whatever returns whatever.

 _signOut = () => signOut()

  render() {
    return (
      <TouchableWithoutFeedback onPress={this._signOut}>

Doesn't work because in _signOut you use another arrow function but this time it returns signOut(), which is invoked right then and there. The weirdness you're seeing probably comes from that fact that at some points that function may not have been imported by the time it's hitting your code and invoking the function.

so the solution is something like this

 _signOut = () => signOut

  render() {
    return (
      <TouchableWithoutFeedback onPress={this._signOut}>

By not invoking the function like you were doing previously, everything works as expected.

Check out this excellent explanation of how to use arrow fuctions inside react: https://stackoverflow.com/a/48700540/214347

Mike Easley
  • 121
  • 7
  • It's also nice to just execute as without the parentheses at all, if there's no parameter need to be passed. – Han Feb 20 '18 at 07:41
1

It seems to be a typescript bug introduces in 2.7.1 - it was very annoying, but good thing is that upgrading to 2.7.2 fixes it. (At least it fixed the issue I experienced).

More info: https://github.com/Microsoft/TypeScript/issues/21478

artur grzesiak
  • 20,230
  • 5
  • 46
  • 56