Typescript Partial But No Undefined

type abc= Partial<{a:number, b:string, c:boolean}>const updateDB=(data:abc)=>{}updateDB({a:1, c:true})
updateDB({a:undefined, b:undefined, c:undefined})
type abc= {a:number, b:string, c:boolean}type PartialButNoUndefined <Type extends Record<string,unknown>,Data extends Record<string,unknown>> = 
keyof Data extends keyof Type
? {
[K in keyof Data]:Data[K] extends Type[K]?Data[K]:`type of property ${K & string} is incorrect`
}
:`unknown property:${Exclude<keyof Data, keyof Type> & string}`
type allProps = PartialButNoUndefined<abc,{a:1,b:"b",c:true}> // {a: 1, b: "b",c: boolean }
type partialProps = PartialButNoUndefined<abc,{b:"b"}> // { b:string }
type propWithIncorrectValue = PartialButNoUndefined<abc,{a:1, b:true}> // {a,:1, b:"type of property b is incorrect" }
type unknownProps = PartialButNoUndefined<abc,{a:1, z:5, u:true}> // "unknown property:z" | "unknown property:u"
  1. detect unknown properties
  2. detect incorrect properties type
const updateDB=<T extends Record<string,unknown>>(data:PartialButNoUndefined<abc,T>)=>{}
updateDB({a: 1, b: "b",c: true }) // expect ok
updateDB({b:"b"}) // expect ok
updateDB({c:undefined}) // expect error
const updateDB=<T extends Record<string,unknown>>(data:T)=>{}
const updateDB=<T extends Record<string,unknown>>(data:PartialButNoUndefined<abc,T>)=>{}
const updateDB=<T extends Record<string,unknown>>(data:T extends never? T: PartialButNoUndefined<abc,T>)=>{}
  1. Now we are clear that we need to assign naked parameter type T to the data argument in order for generic inference to work
  2. But we don’t want to use generic T as data type, we want PartialButNoUndefined<abc,T> our data type
  3. so what data: T extends never? T: PartialButNoUndefined<abc,T> do is telling Typescript: "heh you need to infer the type of thedata argument from user input as T, but the type of data has to be PartialButNoUndefined<abc,T>"
type abc= {a:number, b:string, c:boolean}type PartialButNoUndefined <Type extends Record<string,unknown>,Data extends Record<string,unknown>> = 
{
[K in keyof Data]: Type[K extends keyof Type ? K:never]
}
const updateDB=<T extends Record<string,unknown>>(data:T extends never? T: PartialButNoUndefined<abc,T>)=>{}updateDB({a: 1, b: "b",c: true }) // ok
updateDB({b:"b"}) // ok
updateDB({a:true, b:"abc",c:undefined}) // expect error
updateDB({b:"abc",z:1}) // expect error
type abc= {a:number, b:string, c:boolean}type PartialButNoUndefined <Type extends Record<string,unknown>, Data extends Record<string,unknown>> = 
{
[K in keyof Data]: Type[K extends keyof Type ? K:never]
}
const updateDB=<T extends Record<string,unknown>>(data: PartialButNoUndefined<abc,T>)=>{}updateDB({a: 1, b: "b",c: true }) // ok
updateDB({b:"b"}) // ok
updateDB({a:true, b:"abc",c:undefined}) // expect error
updateDB({b:"abc",z:1}) // expect error

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Acid Coder

Acid Coder

Typescript Zombie. Youtube Pikachu On Acid.