Luke
Luke

Reputation: 8407

Typescript Index Types from an untyped object

So i wanted to have all the icon names in the autocomplete from the react native icons module. Unfortunately the typings they provide do not include the names as an union type.

So my question is, importing an object (that typescript recognizes, with all its keys), how can I get all the keys as a union type.

Currently this is the only thing i came up with

import React from 'react';
import { MaterialCommunityIcons as Icon } from '@expo/vector-icons';
import { IconProps } from '@types/react-native-vector-icons/Icon'
import glyphmap from 'react-native-vector-icons/glyphmaps/MaterialCommunityIcons.json'

// create a type where I can do keyof
type MyMap<T> = {
    [ P in keyof T ]: number
};

// unnecessary? function that maps any input
// to MyMap. 
function something<T>(input: T) : MyMap<T> {
    return (input as any) as MyMap<T>
}

const result = something(glyphmap);

// finally I get all keys from glyphmap as union of string literals    
type MapKeys = keyof MyMap<typeof result>

interface Props extends IconProps {
    name: MapKeys
}

const MyIcon = (props: Props) => (
    <Icon {...props} />
)

// using here the name prop gives me all the keys as autocomplete
const Test = props => (
    <MyIcon name="access-point" />
)

So as you can see, I couldn´t find any other way, how I could convert the glyphmap from a json file to something like this, without passing it through a senseless function

type MyMap<T> = {
    [ P in keyof T ]: number
};

So one more time the question more precise:

How do I convert an untyped object into MyMap without passing it through a function

Upvotes: 2

Views: 772

Answers (1)

Luke
Luke

Reputation: 8407

UPDATE

So after looking into import types (great thanks to Madara Uchiha) the whole thing can be transformed into one line of code... :D

type Glyphmap = typeof import('somemodule/.../file.json')

ORIGINAL

Oh, as soon as I sent the question, I looked over the code again and found that the typeof result could be also directly typeof glyphmap. So I tried and it worked perfectly. So no need of this useless function.

import React from 'react';
import { MaterialCommunityIcons as Icon } from '@expo/vector-icons';
import { IconProps } from '@types/react-native-vector-icons/Icon'
import glyphmap from 'react-native-vector-icons/glyphmaps/MaterialCommunityIcons.json'

type MyMap<T> = {
    [ P in keyof T ]: number
};

// spread keys after converting glyphmap into MyMap
type MapKeys = keyof MyMap<typeof glyphmap>

interface Props extends IconProps {
    name: MapKeys
}

const MyIcon = (props: Props) => (
    <Icon {...props} />
)

const Test = props => (
    <MyIcon name="account" />
)

Upvotes: 2

Related Questions