3

I know that this has been asked-and-answered in What is the TypeScript equivalent of "PropTypes.oneOf" (restrict a variable to subset of values), but I have a case where I don't feel like the answer solves my issue yet.

I am working on converting a project from JavaScript to Typescript. In one React component, a JSON file is imported. One of the props in the component must be one of the keys of this JSON:

import React from "react"
import PropTypes from "prop-types"
import myData from "./myData.json"

const dataKeys = Object.keys(myData)

function MyComponent({myType, ...}) { ... }

MyComponent.propTypes = {
  myType: PropTypes.oneOf(dataKeys).isRequired,
  ...
}

I now want to convert MyComponent into Typescript, so I'm going to remove PropTypes and create a Props interface based off of the existing propTypes. The thing is, I am unsure how to convert PropTypes.oneOf which is built off of an existing variable, especially one that depends on an import of a JSON file. Normally, I would use a union of string literals or an enum type. What are my options in this case?

Yes, I have allowSyntheticDefaultImports enabled in tsconfig.json.

ecbrodie
  • 11,246
  • 21
  • 71
  • 120
  • I have the exact same problem. I tried `type myPropType = keyof typeof myData` which at first seemed to work: `myPropType` is a union of all the key strings. But when I use this type in a component interface it does not typecheck correctly. On usage, the compiler hints tell me that prop has type 'string' | 'number' | 'symbol'. – 4nduril Sep 19 '19 at 19:53

1 Answers1

1

Assuming iconNames is an array, this StackOverflow answer should help: Typescript derive union type from tuple/array values

Basically, when you define iconNames, define the type along with it:

const iconNames = ['plus', 'arrow', 'trash'] as const;
type IconNamesType = typeof iconNames[number];
helloitsjoe
  • 6,264
  • 3
  • 19
  • 32
  • I had made an edit to my question to change `iconNames` to `dataKeys`, which is indeed a string array. I had copied over actual production code and forgotten to anonymize that particular line...my bad. Anyway, I'm happy to hear that this feature was recently added to Typescript. Thank you. – ecbrodie Jul 21 '19 at 03:32
  • Sorry....I just realized that this answer won't help in my case, because I'm using `Object.keys()` to build the array from an import of another file. Const contexts can't be used with these "dynamic arrays", it can only be used with a static array literal. – ecbrodie Jul 21 '19 at 03:38