Home > Software engineering >  Is it possible to use generic parameter value in conditional type result field in Typescript?
Is it possible to use generic parameter value in conditional type result field in Typescript?

Time:08-01

Well, I want to write a bit tricky generic function type for transforming data. For single object it's easy:

export type SingleObjFunction<InputDataType, OutputDataType> =
  (object: InputDataType) => OutputDataType;

However, for array of objects I want the function which return either an object with field: OutputDataType[] property inside, or plain array; Is it possible to get this key of property from another generic parameter, like this:

export type MultipleObjFunction<
  InputDataType, 
  OutputDataType, 
  InnerField extends (string | undefined), 
  FunctionResult = InnerField extends string
    ? { [Key: valueof InnerField]: OutputDataType[] }
    : OutputDataType[]
> = (objs: InputDataType[]) => FunctionResult

I know there is no such thing as valueof, but may be there is another way to do so?

CodePudding user response:

You can use a combination of default type parameters and conditional types to build the type parameter FunctionResult before using it as the return type of your function.

The compiler will use the resolved type of the InnerField type parameter (which is set to undefined by default if no type argument is provided when invoking the function) to make a determination: if that resolved type is assignable to a string, then the return type will be an object type Record<InnerField, OutputDataType[]>, else it will be an array type OutputDataType[].

TS Playground

type MultipleObjFunction<
  InputDataType, 
  OutputDataType, 
  InnerField extends (string | undefined) = undefined,
  FunctionResult = InnerField extends string
    ? Record<InnerField, OutputDataType[]>
    : OutputDataType[]
> = (objs: InputDataType[]) => FunctionResult;

type In = {
  str: string;
  num: number;
};

type Out = { result: string };

declare const arg: In;

declare const f1: MultipleObjFunction<In, Out>;
const r1 = f1([arg]);
    //^? const r1: Out[]

declare const f2: MultipleObjFunction<In, Out, 'myPropertyName'>;
const r2 = f2([arg]);
    //^? const r2: Record<"myPropertyName", Out[]>
type R2Key = keyof typeof r2;
   //^? type R2Key = "myPropertyName"
r2.myPropertyName
 //^? (property) myPropertyName: Out[]

  • Related