TG Person
TG Person

Reputation: 463

TypeScript type that copies another object type, but changes type of properties based on their original type condition

I need a TypeScript type that copies another object type, but changes type of properties based on their original type condition. And also do so to all nested and deep nested properties.

For example a type DateToStrings<T> that would turn all type Date properties into type string properties. It would look like this:

If I have a class:

class Milk {
  brandName: string,
  prince: number,
  dealExpiredAt: Date,
  properties: {
    expirationDetails: {
      expiredAt: Date
    }
  }
}

The type DateToStrings<Milk> would be:

{
  brandName: string,
  price: number,
  dealExpiredAt: string,
  properties: {
    expirationDetails: {
      expiredAt: string
    }
  }
}

Would really appreciate some help as I don't really have a direction to approach it, any tips or known types / type packages that do something similar?

Upvotes: 1

Views: 944

Answers (1)

Aleksey L.
Aleksey L.

Reputation: 37918

You could use recursive conditional type. Not all edge cases covered, but for above example something like this should work:

type DateToStrings<T> = {
    [K in keyof T]: T[K] extends Date
    ? string
    : T[K] extends Array<infer I>
    ? Array<DateToStrings<I>>
    : T[K] extends object
    ? DateToStrings<T[K]>
    : T[K]
}

type MilkTransformed = DateToStrings<Milk>

const foo: MilkTransformed = {
    brandName: 'string',
    prince: 123,
    dealExpiredAt: 'Date',
    properties: {
        expirationDetails: {
            // Expected error: Type 'Date' is not assignable to type 'string'
            expiredAt: new Date
        }
    }
}

Playground

Upvotes: 2

Related Questions