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

RFC: Platform isAndroid, isIOS, isNative properties #670

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
82 changes: 82 additions & 0 deletions proposals/0670-platform-is-platform-props.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
title: Platform isAndroid, isIOS, and isNative properties
author:
- Ryan Linton
date: 2023-06-14
---

# RFC0670: Platform isAndroid, isIOS, and isNative properties

## Summary

Add `isAndroid`, `isIOS`, and `isNative` to `Platform`.

## Basic example

```ts
if (Platform.isAndroid) {
// do some Android only stuff here
}
```

## Motivation

Platform already defines `isPad`, `isTV`, and `isTesting`. In consulting and the companies I've worked at I've seen dozens (even hundreds) of apps, and nearly all backfill the missing ones `isAndroid` and `isIOS` with something along the lines of the following:

```ts
const isAndroid = Platform.OS === "android";
const isIOS = Platform.OS === "ios";
```

`Platform` should provide these since so many devs want to express one-off platform checks this way.

## Detailed design

I did an initial implementation [here](https://github.com/facebook/react-native/pull/37870) but it has some drawbacks. As @NickGerleman [pointed out](https://github.com/facebook/react-native/pull/37870#pullrequestreview-1478897922) we don't want to maintain a centralized list of platforms. A better solution that keeps the platform definitions in their respective platforms is to update `Platform` to be a proxy object.

```ts
const Platform = new Proxy(
{
__constants: null,
OS: "android",
isAndroid: true,
isNative: true,
// ...
},
{
get(target, prop) {
if (prop in target) {
return target[prop];
}

if (prop.toString().startsWith("is")) {
return false;
}

return Reflect.get(...arguments);
},
}
);
```

## Drawbacks

- This change doesn't really offer any new functionality over conditional logic using `Platform.OS`. It's just a different (albeit quite common) way of expressing the same thing.
- As @motiz88 [points out](https://github.com/facebook/react-native/pull/37870#issuecomment-1591225470) this breaks existing optimizations with Babel transforms that remove dead code based on `Platform.OS` conditionals. This proposal likely further complicates that by making `Platform` a proxy object.
- All other platforms would need to update their `Platform` implementations to match.

## Alternatives

Another potential solution that doesn't use proxy but reads similarly would be to add an `is` method (e.g. `Platform.is('android')` or `Platform.is('ios')`). This may or may not have advantages considering the Babel transforms. It is less similar to the common code that inspired this proposal though.

## Adoption strategy

This is not a breaking change but would be a new API offering the same existing functionality provided by checking against `Platform.OS`. Existing React Native developers would upgrade to latest and discover via docs and types.

## How we teach this

Per motivation, React Native developers are already doing this. This just moves the definition of `isAndroid` and `isIOS` up into React Native.

## Unresolved questions

- Where are the Babel transforms for removing platform specific code and how do they work?