typescript

How to define a return type that takes a Record, and returns a Record with the same properties, but with transformed value types


I have a function in which I transform an object's values, somewhat like this:

type InputValue = number | boolean;
type TransformValue<IV extends InputValue> = IV extends number ? "num" : "bool";

const transformObject = <
  Input extends Record<string, InputValue>,
  Key extends keyof Input,
>(
  input: Input,
): Record<K, TransformValue<Input[Key]>> {
  /* ... */
}

except that I would like to be able to encode in the type which property has what type of value.

So for example, if I have an object:

const inputObject: {
  keyA: number;
  keyB: boolean;
} = /* ... */;

I'd like the return type to be:

{
  keyA: "num";
  keyB: "bool";
}

instead of the current Record<"keyA" | "keyB", "num" | "bool">. Is that possible?


Solution

  • So, the transformObject function returns "num" or "bool" as the value for each key in the given object. You can achieve this as follows:

    { [Key in keyof Input]: TransformValue<Input[Key]> }
    
    type InputValue = number | boolean;
    type TransformValue<IV extends InputValue> = IV extends number ? "num" : "bool";
    
    const transformObject = <Input extends Record<string, InputValue>>(
      input: Input
    ): { [Key in keyof Input]: TransformValue<Input[Key]> } => {
      const result: any = {};
      for (const key in input) {
        result[key] = typeof input[key] === "number" ? "num" : "bool";
      }
      return result;
    };
    
    // Test case
    const inputObject = {
      keyA: 42,
      keyB: true,
    };
    // { keyA: number; keyB: boolean; } --> { keyA: "num"; keyB: "bool"; }
    const transformed = transformObject(inputObject);