简体   繁体   中英

How to only collect keys in a type that has an object with some specific key as a value in Typescript interface?

I have a redux state like this

interface DataState {
  dashboard: {
    data: DashboardData | null
    isLoading: boolean
    error: string | null
  }
  policySearch: {
    data: PolicySearchData | null
    isLoading: boolean
    error: string | null
  }
  other: {
    someKey: someValue
  }
}

and I have an action creator that toggles the isLoading state in given field in the data state

toggleDataLoading('policySearch', true)

I don't want to send a wrong first parameter to toggleDataLoading function so I have this:

type FieldsThatHaveLoadingState = 'dashboard' | 'policySearch

because some fields won't have isLoading state

I tried to think of a way to programmatically collect the keys from the DataState with Typescript. Something looks like this in javascript:

const keysIWant = {}
Object.keys(dataState).forEach(key => {
 if(dataState[key].isLoading) keysIWant[key] = true
})
type FieldsThatHaveLoadingState = keyof typeof keysIWant

Is it possible to do this kind of a collection only using Typescript types and checks?

The approach shown below correctly limits valid keys to the function call.

The complexity of having to have nested distributive conditionals to express this will hopefully go away with the work on https://github.com/microsoft/TypeScript/issues/23188

interface DataState {
  dashboard: {
    isLoading: boolean
  }
  policySearch: {
    isLoading: boolean
  }
  other: {
    someKey: 'someValue'
  }
}

type LoadableKey<T = keyof DataState> = T extends keyof DataState ? DataState[T] extends { isLoading: boolean } ? T : never : never

const toggleDataLoading = (stateKey: LoadableKey) => {
  console.log(`Loading ${stateKey}`)
}

toggleDataLoading('dashboard');

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