AWS DynamoDB doesn't store Date values, so all date/time values need to be serialized into ISO 8601 strings before storing, and then need to be deserialized from strings to Date when retrieving.
I've created a pair of generic TypeScript helper functions to do this serialization and deserialization. But I'm not sure how to make these functions type-safe. I also don't want to deal with maintaining pairs of normal vs. serialized types-- instead I just want to define the "normal" type and use a generic type definition to define the serialized type.
Specifically, given some type T which may have Date-typed properties (either at top level or in nested objects) I want to create a type definition for Serialized<T> that has the same shape as T except that all Date-typed properties are replaced with string. Is this possible?
For example, given an object that looks like this:
interface OriginalType {
  foo: Date, 
  bar: number, 
  nested: { 
    created: Date 
  } 
}
I want to end up with a type like the one below: (but without manually typing in the definition)
interface SerializedType {
  foo: string, 
  bar: number, 
  nested: { 
    created: string
  } 
}
What should be the declaration for Serialized<T>?
You are looking for a recursive homomorphic mapped type (to iterate over the fields) using a conditional type (to check whether each field is a date).
type Serialized<T> = {
    [P in keyof T]: T[P] extends Date ? string : Serialized<T[P]>
};
This solution takes advantage of the special rule that applying a homomorphic mapped type such as Serialized to a primitive type returns the primitive type, regardless of the body of the homomorphic mapped type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With