--- title: "Get inferred type for a generic parameter in TypeScript" date: 2023-01-28T14:50:54-05:00 toc: false images: tags: - dev - typescript --- Have you used [Zod](https://zod.dev/)? It's a very cool TypeScript library for schema validation. Compared to alternatives like Joi, one of the biggest strenghts of Zod is that it can do type inference. For example, ```ts const PersonSchema = z.object({ name: z.string(), age: z.number(), }); type Person = z.infer; // This is equivalent to { name: string; age: number; } ``` Now I was recently working on a database client, where I'm using a validator function to ensure the data on the database matches what the client expects. I then take advantage of TypeScript's type inference so the type of everything matches. It looks like this: ```ts class Database { constructor(validator: (input: unknown) => T); function get(key: string): T | undefined { /* ... */ } function put(key: string, data: T) { /* ... */ } } // Note I didn't have to specify the type parameter, // TypeScript infers it from the validator argument const PersonDB = new Database(PersonSchema.parse); ``` At this point I started to wonder, could I do something similar to what Zod does and get the inferred type for the objects that are stored in the database? While this is not required in this example above since I could get the type from Zod, the validator function doesn't necessarily have to be implemented with Zod. After reading through Zod's codebase, I found the trick they use, and it's very simple. Let's see it: ```ts class Database { readonly _output!: T; constructor(validator: (input: unknown) => T); function get(key: string): T | undefined { /* ... */ } function put(key: string, data: T) { /* ... */ } } type EntityOf> = D["_output"]; const PersonDB = new Database(PersonSchema.parse); type Person = EntityOf; ``` This is surprisingly simple. We add a property `_output` to the class, which has the inferred type. We can then get the type through that property with `D["_output"]`. The `!` in the definition of the property is there because we never actually set any value for `_output`. TypeScript normally will detect and warn us that we did not set `_output`, but the exclamation point suppresses that. This is not without drawbacks of course, because the `_output` property will be visible in the instances of the class. We can't hide the property with `private` because TypeScript won't let us look it up in `EntityOf` if we do so. So the best we can do is document the fact that this should not be used, and throw in the prefix so it stands out from regular properties.