colinwurtz
colinwurtz

Reputation: 723

Recursive generics and Array inference

I'm trying to create a few generic recursive types to modify structure of existing types. I can't tell why the sections inferring arrays and nested objects is not getting triggered. Any idea what I'm doing wrong?

TS playround link with the below code:

//Generics
type WithConfidence<T> = {
  [Property in keyof T]: {
    value: FieldWithConfidence<T[Property]>;
    confidence: number;
  };
};

type FieldWithConfidence<T> = {
  [P in keyof T]: T[P] extends string | number | Date
    ? T[P]
    : T[P] extends Array<infer U>
    ? {
        confidence: number;
        value: Array<WithConfidence<U>>;
      }
    : {
        value: FieldWithConfidence<T[P]>;
        confidence: number;
      };
};

It works for primitive types and when the type is an object, just not an array. Here's an example illustrating where it falls short.

type Asset = {
  AssetCode?: string;
  Contracts?: Array<Contract>;
  Warranty: WarrantyInfo;
};

type Contract = {
  ContractNumber: string;
};

type WarrantyInfo = {
  Purchased: Date;
};

const value: WithConfidence<Asset> = {
  Warranty: {
    confidence: 500,
    value: {
      Purchased: {
        value: new Date(), //Error
        confidence: 500,
      },
    },
  },
  AssetCode: {
    value: "123",
    confidence: 100,
  },
  Contracts: {
    confidence: 400,
    value: [
      {
        ContractNumber: { //Error
          value: "123",
          confidence: 500,
        },
      },
    ],
  },
};

Upvotes: 0

Views: 672

Answers (1)

kdau
kdau

Reputation: 2099

Assuming what I mentioned in my comment on your question, the fix is just to simplify your FieldWithConfidence type significantly. Right now it is trying to add a number of additional levels of structure beyond what you seem to want. Here is a version of that type that works as I think you intend:

type FieldWithConfidence<T> =
  T extends boolean | string | number | Date
    ? T
    : T extends Array<infer U>
      ? Array<FieldWithConfidence<U>>
      : WithConfidence<T>;

Here's a working playground link with that change.

Upvotes: 3

Related Questions