In the discussion on #328 the consensus seems to be that people like type definitions. This moves toward generating types using jsdoc as suggested by @bollwyvl in that thread.

I don't have much Typescript experience so I would very much appreciate it if people could test them out. The types are available as CircleCI artifacts here:
https://3914-322074228-gh.circle-artifacts.com/0/root/repo/build/pyodide.d.ts

@bollwyvl said that

> types that aren't tested are probably worse than no types at all

If anyone could contribute tests, that would be very helpful (I don't know what they should look like). 

The main limitation I ran into with this approach is that Typescript supports Typescript types in jsdoc annotations but jsdoc does not. This means that if we want to automatically generate docs, we have to stick to the much more limited syntax that jsdoc supports. For example, `isPyProxy` should be typed `obj is PyProxy` but this approach does not allow that as far as I can tell. 
Some basic types. In the discussion on #328 the consensus seems to be that people like type definitions. This moves toward generating types using jsdoc as suggested by @bollwyvl in that thread.

I don't have much Typescript experience so I would very much appreciate it if people could test them out. The types are available as CircleCI artifacts here:
https://3914-322074228-gh.circle-artifacts.com/0/root/repo/build/pyodide.d.ts

@bollwyvl said that

> types that aren't tested are probably worse than no types at all

If anyone could contribute tests, that would be very helpful (I don't know what they should look like). 

The main limitation I ran into with this approach is that Typescript supports Typescript types in jsdoc annotations but jsdoc does not. This means that if we want to automatically generate docs, we have to stick to the much more limited syntax that jsdoc supports. For example, `isPyProxy` should be typed `obj is PyProxy` but this approach does not allow that as far as I can tell. 
#!/usr/bin/env bash

PYODIDE_IMAGE_REPO="pyodide"
PYODIDE_IMAGE_TAG="16"
PYODIDE_PREBUILT_IMAGE_TAG="0.17.0"
DEFAULT_PYODIDE_DOCKER_IMAGE="${PYODIDE_IMAGE_REPO}/pyodide-env:${PYODIDE_IMAGE_TAG}"
DEFAULT_PYODIDE_SYSTEM_PORT="8000"
DOCKER_COMMAND="/bin/bash"

set -eo pipefail


function usage() {
  cat > /dev/stdout <<EOF
Usage: run_docker [OPTIONS] [COMMAND] [ARG...]

Runs COMMAND in a new Pyodide docker container. If no COMMAND is provided, starts a bash
shell in the container.

Options:
  -h, --help                  Show this information and exit.
  --pre-built                 Use the prebuilt Pyodide image.
                              This is ignored if the env var PYODIDE_DOCKER_IMAGE is set.
  -p, --port <port>           System port to which to forward.
                              This is ignored if the env var PYODIDE_SYSTEM_PORT is set.
                              If set to 'none', docker instance will not bind to any port.

Prerequisites:
  Docker has to be set up on your system.
EOF
}

function error() {
  usage
  exit 255
}

while [[ $# -gt 0 ]]
do
  key="$1"
  case $key in
      -h|--help)
        usage
        exit 0
      ;;
      --pre-built)
        if [[ -n ${PYODIDE_DOCKER_IMAGE} ]]; then
          echo "WARNING: will use the env var PYODIDE_DOCKER_IMAGE=${PYODIDE_DOCKER_IMAGE},
          the flag --pre-built has no effect"
        fi
        DEFAULT_PYODIDE_DOCKER_IMAGE="pyodide/pyodide:${PYODIDE_PREBUILT_IMAGE_TAG}"
        shift
      ;;
      -p|--port)
        if [ "$#" -lt 2 ]; then
          >&2 echo "port cannot be empty"
          error
        fi
        if [[ -n ${PYODIDE_SYSTEM_PORT} ]]; then
          echo "WARNING: will use the env var PYODIDE_SYSTEM_PORT=${PYODIDE_SYSTEM_PORT} instead of the provided port"
        fi
        DEFAULT_PYODIDE_SYSTEM_PORT=$2
        shift 2
      ;;
      -*)
        >&2 echo "Unknown option $1"
        error
      ;;
      *)
        DOCKER_COMMAND="$@"
        break
      ;;
  esac
done

PYODIDE_DOCKER_PORT=${PYODIDE_DOCKER_PORT:-"8000"}
PYODIDE_SYSTEM_PORT=${PYODIDE_SYSTEM_PORT:-${DEFAULT_PYODIDE_SYSTEM_PORT}}
PYODIDE_DOCKER_IMAGE=${PYODIDE_DOCKER_IMAGE:-${DEFAULT_PYODIDE_DOCKER_IMAGE}}

# in case the port is not a number, do not bind the port
case $DEFAULT_PYODIDE_SYSTEM_PORT in
  none)
  PORT_CONFIGURATION_LINE=""
  ;;
  ''|*[!0-9]*) # contains a non-digit character, therefore it is not a number
  echo "WARNING: Invalid port argument '$DEFAULT_PYODIDE_SYSTEM_PORT'. Port binding disabled."
  PORT_CONFIGURATION_LINE=""
  ;;
  *)
  PORT_CONFIGURATION_LINE="-p $PYODIDE_SYSTEM_PORT:$PYODIDE_DOCKER_PORT"
  ;;
esac

mkdir -p .docker_home

USER_HOME="/src/.docker_home"
USER_NAME="$(id -u -n)"
USER_PASS="x"
USER_ID="$(id -u)"
USER_GID=0
USER_COMMENT_FIELD="${USER_NAME} pyodide user alias"
USER_INTERPRETER="/sbin/nologin"
USER_ACCOUNT_INFO="${USER_NAME}:${USER_PASS}:${USER_ID}:${USER_GID}:${USER_COMMENT_FIELD}:${USER_HOME}:${USER_INTERPRETER}"

# Start a detached container as root, add the host uname and uid to /etc/passwd,
# then run forever
CONTAINER=$(\
  docker run \
    -d --rm \
    -v $PWD:/src \
    --user root \
    --shm-size 2g \
    "${PYODIDE_DOCKER_IMAGE}" \
    /bin/bash -c " \
      echo '${USER_ACCOUNT_INFO}' >> /etc/passwd ; \
      tail -f /dev/null \
    " \
)

EXIT_STATUS=0
# Execute the provided command as the host user with HOME=/src
docker exec \
  -it \
  --user $(id --user):$(id --group) \
  $CONTAINER \
  /bin/bash -c "${DOCKER_COMMAND}" || EXIT_STATUS=$?

docker kill $CONTAINER > /dev/null
exit $EXIT_STATUS

#!/usr/bin/env bash

PYODIDE_IMAGE_REPO="pyodide"
PYODIDE_IMAGE_TAG="16"
PYODIDE_PREBUILT_IMAGE_TAG="0.17.0"
DEFAULT_PYODIDE_DOCKER_IMAGE="${PYODIDE_IMAGE_REPO}/pyodide-env:${PYODIDE_IMAGE_TAG}"
DEFAULT_PYODIDE_SYSTEM_PORT="8000"
DOCKER_COMMAND="/bin/bash"

set -eo pipefail


function usage() {
  cat > /dev/stdout <<EOF
Usage: run_docker [OPTIONS] [COMMAND] [ARG...]

Runs COMMAND in a new Pyodide docker container. If no COMMAND is provided, starts a bash
shell in the container.

Options:
  -h, --help                  Show this information and exit.
  --pre-built                 Use the prebuilt Pyodide image.
                              This is ignored if the env var PYODIDE_DOCKER_IMAGE is set.
  -p, --port <port>           System port to which to forward.
                              This is ignored if the env var PYODIDE_SYSTEM_PORT is set.
                              If set to 'none', docker instance will not bind to any port.

Prerequisites:
  Docker has to be set up on your system.
EOF
}

function error() {
  usage
  exit 255
}

while [[ $# -gt 0 ]]
do
  key="$1"
  case $key in
      -h|--help)
        usage
        exit 0
      ;;
      --pre-built)
        if [[ -n ${PYODIDE_DOCKER_IMAGE} ]]; then
          echo "WARNING: will use the env var PYODIDE_DOCKER_IMAGE=${PYODIDE_DOCKER_IMAGE},
          the flag --pre-built has no effect"
        fi
        DEFAULT_PYODIDE_DOCKER_IMAGE="pyodide/pyodide:${PYODIDE_PREBUILT_IMAGE_TAG}"
        shift
      ;;
      -p|--port)
        if [ "$#" -lt 2 ]; then
          >&2 echo "port cannot be empty"
          error
        fi
        if [[ -n ${PYODIDE_SYSTEM_PORT} ]]; then
          echo "WARNING: will use the env var PYODIDE_SYSTEM_PORT=${PYODIDE_SYSTEM_PORT} instead of the provided port"
        fi
        DEFAULT_PYODIDE_SYSTEM_PORT=$2
        shift 2
      ;;
      -*)
        >&2 echo "Unknown option $1"
        error
      ;;
      *)
        DOCKER_COMMAND="$@"
        break
      ;;
  esac
done

PYODIDE_DOCKER_PORT=${PYODIDE_DOCKER_PORT:-"8000"}
PYODIDE_SYSTEM_PORT=${PYODIDE_SYSTEM_PORT:-${DEFAULT_PYODIDE_SYSTEM_PORT}}
PYODIDE_DOCKER_IMAGE=${PYODIDE_DOCKER_IMAGE:-${DEFAULT_PYODIDE_DOCKER_IMAGE}}

# in case the port is not a number, do not bind the port
case $DEFAULT_PYODIDE_SYSTEM_PORT in
  none)
  PORT_CONFIGURATION_LINE=""
  ;;
  ''|*[!0-9]*) # contains a non-digit character, therefore it is not a number
  echo "WARNING: Invalid port argument '$DEFAULT_PYODIDE_SYSTEM_PORT'. Port binding disabled."
  PORT_CONFIGURATION_LINE=""
  ;;
  *)
  PORT_CONFIGURATION_LINE="-p $PYODIDE_SYSTEM_PORT:$PYODIDE_DOCKER_PORT"
  ;;
esac

mkdir -p .docker_home

USER_HOME="/src/.docker_home"
USER_NAME="$(id -u -n)"
USER_PASS="x"
USER_ID="$(id -u)"
USER_GID=0
USER_COMMENT_FIELD="${USER_NAME} pyodide user alias"
USER_INTERPRETER="/sbin/nologin"
USER_ACCOUNT_INFO="${USER_NAME}:${USER_PASS}:${USER_ID}:${USER_GID}:${USER_COMMENT_FIELD}:${USER_HOME}:${USER_INTERPRETER}"

# Start a detached container as root, add the host uname and uid to /etc/passwd,
# then run forever
CONTAINER=$(\
  docker run \
    -d --rm \
    -v $PWD:/src \
    --user root \
    --shm-size 2g \
    "${PYODIDE_DOCKER_IMAGE}" \
    /bin/bash -c " \
      echo '${USER_ACCOUNT_INFO}' >> /etc/passwd ; \
      tail -f /dev/null \
    " \
)

EXIT_STATUS=0
# Execute the provided command as the host user with HOME=/src
docker exec \
  -it \
  --user $(id --user):$(id --group) \
  $CONTAINER \
  /bin/bash -c "${DOCKER_COMMAND}" || EXIT_STATUS=$?

docker kill $CONTAINER > /dev/null
exit $EXIT_STATUS
