Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow passing additional SupportedExtensions to support React Native .android and .ios module loading #8328

Closed
dfguo opened this issue Apr 27, 2016 · 17 comments
Labels
Duplicate An existing issue was already created Suggestion An idea for TypeScript

Comments

@dfguo
Copy link

dfguo commented Apr 27, 2016

We are using TypeScript to write our React Native application and encountered an issue with platform specific extensions provided by RN.

React Native will detect when a file has a .ios. or .android. extension and load the right file for each platform when requiring them from other components.

For example, you can have these files in your project:

BigButton.ios.js
BigButton.android.js

With this setup, you can just require the files from a different component without paying attention to the platform in which the app will run.

import BigButton from './components/BigButton';

When we use tsc to compile our code, it won't recognize the android or ios platform extension. What about have a customPlatform option that's similar to allowJs that auto prepend the platform name to supportedTypeScriptExtensions?

function getSupportedExtensions(options) {
        if (options && options.customPlatform) {
          return ts.supportedTypeScriptExtensions.concat(ts.supportedTypeScriptExtensions.map((ext) => `.${options.customPlatform}${ext}`))
        }
        return options && options.allowJs ? allSupportedExtensions : ts.supportedTypeScriptExtensions;
    }
@zhengbli
Copy link
Contributor

I think this problem might be better solved with the glob pattern support in tsconfig.json (#5980). Modifying getSupportedExtensions wouldn't scale.

@dfguo
Copy link
Author

dfguo commented Apr 27, 2016

Makes sense. Love to see that change going in soon. Currently blocking our RN project.

@mhegazy
Copy link
Contributor

mhegazy commented Apr 27, 2016

Do not think globs will help here. the suggesion in the OP seems like a valid one. we should allow additional lookup locations, so that users can specify that, so "additionalExtensions" : [ "ios.ts", "ios.tsx", "android.ts", "android.tsx" ].

the workaround for now, would be create a .d.ts file next to your platform specific modules, something like:

/// components/BigButton.d.ts
export * from "./BigButton.ios"; 

this way your import for ./components/BigButton will resolve to ./components/BigButton.d.ts at design time getting you the shape of the module. and at runtime, it should do the right thing and bind to the platform specific version. there should not be any additional changes required.

@mhegazy mhegazy added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Apr 27, 2016
@mhegazy mhegazy changed the title React Native .android and .ios support Allow passing additional SupportedExtensions to support React Native .android and .ios module loading Apr 27, 2016
@saulshanabrook
Copy link

@mhegazy If the exported types in BigButton.android.tsx diverges accidentally from BigButton.ios.tsx, then this won't be picked up at compile time, correct?

Is it possible to keep full compile time type checking?

@mhegazy
Copy link
Contributor

mhegazy commented May 14, 2016

The compiler does not know that BigButton.android.tsx and BigButton.ios.tsx are two implementation of the same module, and thus, should have the same shape. so they could diverge.

One possible solution here is to have modules implement interfaces, as previously suggested in #420. This will force the compiler to check the shape of the module against an interface.

@mhegazy
Copy link
Contributor

mhegazy commented May 16, 2016

here is another workaround to get it to type check today, courtesy of @RyanCavanaugh:

import * as ios from "./BigButton.ios"; 
import * as android from "./BigButton.ios"; 

declare var _test: typeof ios;
declare var _test: typeof android;

/// export to get the shape of the module
export * from "./BigButton.ios"; 

now if ios and android ever diverge, you will get an error on the redeclaration of _test. no code will be generated for this.

@mhegazy
Copy link
Contributor

mhegazy commented May 17, 2016

Recommendations here is to use path mapping support, see https://github.com/Microsoft/TypeScript-Handbook/blob/release-2.0/pages/Module%20Resolution.md#path-mapping

so your tsconfig.json should contain something like:

{
    "compilerOptions": {
        "paths": {
            "*": ["*", "*.ios", "*.android"]
        }
   }
}

this will tell the compiler when resolving an import to BigButton to look at:

  • BigButton.tsx
  • BigButton.ios.tsx
  • BigButton.androdid.tsx

For checking that the different implementation for the modules all have the same shape is tracked by #420

@mhegazy
Copy link
Contributor

mhegazy commented May 17, 2016

closing in favor of #420

@mhegazy mhegazy closed this as completed May 17, 2016
@mhegazy mhegazy added Duplicate An existing issue was already created and removed In Discussion Not yet reached consensus labels May 17, 2016
@saulshanabrook
Copy link

saulshanabrook commented May 23, 2016

@mhegazy How can I use the paths compiler option? It isn't documented in the Compiler Options documentation.

@mhegazy
Copy link
Contributor

mhegazy commented May 23, 2016

Paths is a TS 2.0 feature. documentation is available at: https://github.com/Microsoft/TypeScript-Handbook/blob/release-2.0/pages/Module%20Resolution.md#path-mapping

should be merged in main documentation once 2.0 ships out.

@sondremare
Copy link

@mhegazy As far as I can tell (when testing it) the path mapping solution only applies to non-relative imports. So I cannot import A from '../otherfolder/stuff'. Am I missing something obvious here? Any help is appreciated

grahammendick added a commit to grahammendick/navigation that referenced this issue Dec 17, 2016
Typescript didn't like import('NavigationBackAndroid') because it there
isn't a NavigationBackAndroid.ts
(microsoft/TypeScript#8328). The workarounds
in the issue don't seem right so just used require directly instead of
import. Need to import specific files so that they appear in the built
package
@dccarmo
Copy link

dccarmo commented Jul 18, 2017

Having the same issue as @sondremare. Is there an updated recommended way to deal with this particular RN feature?

@eldenpark
Copy link

Can't believe this issue still persists. The idea of allowing custom extension, or more specifically a filename suffix support, with ts or tsx at the end as in file.suffix.ts would be a great plus to the language.

@sharplet
Copy link

@mhegazy This was closed in favour of #420, but as @sondremare mentioned the "paths" option doesn't work for relative imports, and #420 doesn't cover that. Any plans to address it?

@mhegazy
Copy link
Contributor

mhegazy commented Oct 5, 2017

Any plans to address it?

it is not clear what path mapping means with a relative path. so no plans really.,

@tommasoresti
Copy link

tommasoresti commented Dec 15, 2017

i think that at this point the "umbrella" solution is the way to go.
On our index files we should tell to the compiler which components are needed at compile time.

having something like this on my index file (that is platform specific) for me makes sense:
index.ios.ts:
export * from "./BigButton.ios";

index.android.ts:
export * from "./BigButton.android";

@simonbuchan
Copy link

Note that with webpack resolve.extensions this isn't necessarily a RN-specific issue, you could, for example have .ltr.tsx and .rtl.tsx variants, or .client.ts and .server.ts for isomorphic apps, etc..., essentially any time you may have multiple output bundles that should be using different code.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

10 participants