简体   繁体   中英

Typescript: How to use a symbol as a key when destructuring a hash

type UseStateTuple<T> = [T,React.Dispatch<React.SetStateAction<T>>]
const StoreContext = createContext<IStore | null>(null)
interface IStore {
  people: UseStateTuple<string[]>
  // IStore could potentially have other useState tuples. Something like
  // posts: UseStateTuple<IPost[]> for example
}

interface Props {
  type: string        // this is the key that points to a useState tuple
  description: string // ignore this
}

export const AddPerson: React.FC<Props> = ({type, description}) => {
  const [input, setInput] = useState('')

  // useContext(StoreContext) returns an IStore object that I want to destructure.
  // In this context (no pun intended) "[type]:" should be evaluated to "people:", right?
  //
  // I can use:
  //   "{ people }"
  //
  // instead of
  //   "[type]: [data, setData]"
  //
  // and it works. Why is that? 
  const { [type]: [data, setData] } = useContext(StoreContext)!

  /*
  // This code works fine.
  const { people } = useContext(StoreContext)!
  const [data, setData] = people
  */

  // function continues....
}

/// JSX
<AddPerson type="people" description="Here is a description..." />

If you need more information about this simple useContext / useState with Typescript example, the three most relevant files (and the whole project) is located here . I tried to put all of the relevant code here in the post.

you may want

interface Props {
  type: keyof IStore        // this is the key that points to a useState tuple
  description: string // ignore this
}

Generally to use an index the indexing expression must be of type keyof T where T is whatever type you are indexing. Or in other words the indexing expression must provably be valid as an index of T .

If you change type to keyof IStore it will work:

import React, { createContext, useState, useContext } from 'react'

type UseStateTuple<T> = [T, React.Dispatch<React.SetStateAction<T>>]
const StoreContext = createContext<IStore | null>(null)
interface IStore {
  people: UseStateTuple<string[]>
  // IStore could potentially have other useState tuples. Something like
  // posts: UseStateTuple<IPost[]>
}

interface Props {
  type: keyof IStore        
  description: string 
}

export const AddPerson: React.FC<Props> = ({type, description}) => {
  const [input, setInput] = useState('')

  const { [type]: [data, setData] } = useContext(StoreContext)!

  return <div></div>
}

let d = () => <AddPerson type="people" description="Here is a description..." /> 

//error
let d2 = () => <AddPerson type="people2" description="Here is a description..." /> 

Playground Link

You may have issues invoking the set method as it will be of a union type, so type assertions may be needed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM