Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert all Date properties (including nested) to string in a TypeScript generic type

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>?

like image 601
Justin Grant Avatar asked Oct 26 '25 00:10

Justin Grant


1 Answers

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.

like image 66
Matt McCutchen Avatar answered Oct 28 '25 18:10

Matt McCutchen