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.
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 ""
}
}
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!
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.