Created
June 2, 2023 21:44
-
-
Save worc/55824c6d910f8a2739b15aa20203abb0 to your computer and use it in GitHub Desktop.
Type algebra to detect empty objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This came out of some work where we were sending an encoded JSON object as a query param in a network call. | |
* But, we can't send nothing, `param=`, or we crash the server, that's taken care of by restricting the type | |
* to at least `Record<string, string>`, but it left open the possibility of empty objects. Encoded as `'%7B%7D'`. | |
* | |
* So I went looking and it's definitely possible to restrict empty objects, but the type algebra is wild. And | |
* it makes use of something people are calling F-bounded quantification. And the error message isn't every helpful. | |
* | |
* See: | |
* - https://stackoverflow.com/a/72554458/769780 | |
* - https://stackoverflow.com/a/72420133/769780 | |
*/ | |
// One of many "canonical" ways to describe an empty object: | |
type EmptyObject = Record<string, never>; | |
type NonEmptyObject<T extends Record<string, unknown>> = T extends EmptyObject | |
? never | |
: T; | |
export default function encodeQueryObject<T extends Record<string, unknown>>( | |
queryObject: NonEmptyObject<T>, | |
) { | |
return encodeURIComponent(JSON.stringify(queryObject)); | |
} | |
// This is I think why they say the generic is self-referential, when | |
// calling the function we don't provide a generic, but let the argument's | |
// own implicit type determine the type algebra: | |
const empty = {}; | |
encodeQueryObject(empty) // TS2345: Argument of type '{}' is not assignable to parameter of type 'never'. | |
const notEmpty = { | |
jquery: '123', | |
}; | |
encodeQueryObject(notEmpty) // No error |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment