Skip to content

Instantly share code, notes, and snippets.

@sidola
Created July 5, 2022 07:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sidola/8b403e69e1513f9443fa761d1af5c968 to your computer and use it in GitHub Desktop.
Save sidola/8b403e69e1513f9443fa761d1af5c968 to your computer and use it in GitHub Desktop.
Ensures a given property is defined and changes its type accordingly.
/**
* Creates a new type where prop T on object K is required and
* non-nullable.
*/
type DefinedProp<T, K extends keyof T> = (
Omit<T, K> &
{ [key in K]-?: Exclude<T[key], undefined> }
)
/**
* For the given object and key, ensures the property at the given key
* is defined and forces the type to reflect that.
*
* It's basically a nested `assertDefined` with a return. If there's
* an easier way to get TS to remember scoped null checks on nested
* properties I'd like to know about it.
*
* @example
* type City = { street: string, zip: number }
*
* // Notice 'city' is optional, we're going to ensure that is defined
* type Data = { name: string, city?: City | undefined }
*
* const data: Data = {
* name: 'Bob',
* city: {
* street: 'Some street',
* zip: 12345
* }
* }
*
* const withCityDefined = assumeDefined(data, 'city')
*
* // 'city' is guaranteed to be defined here
* console.log(withCityDefined.city.street)
*/
export function assumeDefined<T, K extends keyof T>(obj: T, key: K): DefinedProp<T, K> {
if (obj[key] == null) {
throw Error(`Property ${String(key)} in ${JSON.stringify(obj)} was not defined`)
}
return obj as unknown as DefinedProp<T, K>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment