简体   繁体   中英

Find type alias based on its property value in TypeScript

I am trying to write some types for executing Cloud Functions. I have a bunch of types like that, each in a separate file.

export type TAddRegistration = {
  name: 'addRegistration'
  data: TAddRegistrationData
  result: TAddRegistrationCallResult
}
export type TSignIn = {
  name: 'signIn'
  data: TSignInData
  result: TSignInCallResult
}

Now ultimately, I want to have a function in client-side code like this and based on passed function name it should provide correct data and result types.

function useCloudFunction(name: TFunctionName) {
  return (data: TFunctionData): TFunctionResult => {
     ...
  }
}

The first step is to declare TFunctionName. This approach works and I am not aware of a better one.

export type TFunctions = TAddRegistration | TSignIn
export type TFunctionName = Pick<TFunctions, 'name'>['name']

The second step is how to discover proper type alias based on the name argument passed into the function and that's where I am stumbling in the dark. Some sort of opposite "Pick" that can lookup in the TFunctions alias.

I can surely structure those aliases differently if there is some nicer way how to approach this.

Update:

This playground is probably the closest I could get, but not exactly desired outcome...

Maybe there's a better way, but something like this would work:

type SpecialFunction<T> = T extends TSignIn['name'] ? TSignIn
  : T extends TAddRegistration['name'] ? TAddRegistration
  : never;

function useFunction<T extends TFunctionName>(name: T) {
  return (data: SpecialFunction<T>['data']): SpecialFunction<T>['result'] => {
    return ""
  }
}

Playground Link

I'd define your types like this:

type TFunctions = TSignIn | TAddRegistration
function useFunction<N extends TFunctions["name"]>(name: N) {
  type TFunc = Extract<TFunctions, { name: N }>
  return (data: TFunc["data"]): TFunc["result"] => {
    return ""; // impl?!
  }
}

You don't need Pick<TFunctions, "name">["name"] because that's equivalent to TFunctions["name"] . Other than that the only difference between your original code and mine is that mine is generic in N , the type of the name parameter. This allows the compiler to remember which value name is, and strongly type the return type:

const signIn = useFunction("signIn");
const signInCallResult = signIn({ email: "okay" }); // TSignInCallResult
signIn({ phone: "oops" }); // error! needs TSignInData
const addReg = useFunction("addRegistration");
const addRegCallResult = addReg({ phone: "okay" }); // TAddRegistrationCallResult
addReg({ email: "oops" }) // error! needs TAddRegistrationData

Looks good to me. Okay, hope that helps; good luck!

Link to code

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