Stack Exchange
Simplify/Reduce/Combine complicated intersection type
I'm working on a library called loudo-check that lets you define a schema for objects, then use that schema to check
that input json conforms to the schema:
import { Check } from "loudo-check"

const userSchema = Check.define({
  id: { v:"", min:36, max:36 },
  email:{ v:"", regex:/[a-z0-9]+@[a-z]+\.[a-z]{2,3}/ },
  name:{ v:"", min:1, max:100 },
  thumbnail: { v:"", regex:/^https:\/\//, required:false }
})

type User = typeof userSchema

const inputJSON = `
{
  "id":"1234",
  "email":"fake@example.com",
  "name":"Flugelhorn"
}
`

const user = Check.parse(userSchema, inputJSON)

I'm pretty happy with it, but the type of the output of define is an intersection type of mandatory properties and optional properties. Conceptually, it's:
type Schema = Record<string,Property<any>>

type Has<S extends Schema,P extends keyof S> = 
  S[P]["required"] extends false ? "N" : "Y"

type Mandatory<S extends Schema> = 
  { [P in keyof S as Has<S,P> extends "Y" ? P : never]: S[P]["v"] }

type Optional<S extends Schema> = 
  { [P in keyof S as Has<S,P> extends "N" ? P : never]?: S[P]["v"] }

type Result<S extends Schema> = Mandatory<S> & Optional<S>

function define<S extends Schema>(schema:S):Result<S> { /* ... */ }

So, for the above userSchema, Result<S> is:
{
  id: string
  email: string
  name: string
}
&
{
  thumbnail?: string
}

I would instead like the type to be:
{
  id: string
  email: string
  name: string
  thumbnail?: string
}

That is, I want to somehow "combine" the intersection into a single type. Is that possible in TypeScript? If so, how do you do it? (And what's it actually called?)
(Note that loudo-check also lets you extend the type with getters or functions, so the intersection potentially consists of four very complicated things that I'd like to just combine into a single type.)
I did try google, but couldn't find anything, because I'm not even sure what the proper terminology here is. What I'd like is some sort of "Simplify" utility type, eg:
type Result<S extends Schema> = Simplify<Mandatory<S> & Optional<S>>


• Please [edit] the code here to be a [mre] where pasting into a standalone IDE will clearly indicate your issue. third party / private / undeclared things are not ideal (what's Property<any>? Are we supposed to find and import "loudo-check" to see the issue?)  • Presumably you're looking for a mapped type as shown in this playground link. Is that right or am I missing something?
