0

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,
        },
      },
    ],
  },
};
2
  • 1
    I have most of an answer ready, but I need to clarify one aspect: in your "Target" comment, you show each item in the Contracts array being an object with a plain ContractNumber property (not turned into a confidence-value object itself), but with a confidence property alongside that property. However, in your sample data, you have ContractNumber turned into a confidence-value object, consistent with the rest of the pattern. I assume you intend the latter? Commented Jun 15, 2021 at 0:52
  • You are correct. I'm going to update the question with an updated TS playground to remove that to avoid confusion. Commented Jun 15, 2021 at 13:09

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.