Skip to content

Instantly share code, notes, and snippets.

Created January 14, 2022 18:21
Show Gist options
  • Save gabrielelana/07ebf8f6a33f9e2c50eebae2a9bff838 to your computer and use it in GitHub Desktop.
Save gabrielelana/07ebf8f6a33f9e2c50eebae2a9bff838 to your computer and use it in GitHub Desktop.
Keep the inferred type but check if it's compatible with some structure
type CompanyName = "dallbogg" | "wakam"
type ActionNames = ["Quote", "Save", "Emit"]
type ActionName = ActionNames[number]
type Tuple<X, Y> = [X, Y];
type CompatibleWith<X, Y> = X extends Y ? Tuple<X, true> : Tuple<X, false>;
type Equals<X, Y> = [X] extends [Y] ? [Y] extends [X] ? Tuple<Y, true> : Tuple<Y, false> : Tuple<Y, false>
type AssertNot<X extends Tuple<any, false>> = X extends Tuple<infer Y, false> ? Y : never;
type Assert<X extends Tuple<any, true>> = X extends Tuple<infer Y, true> ? Y : never;
const assertUnreacheable = (x: never): never => { throw new Error() };
type CompanyConfiguration = {
readonly name: CompanyName,
readonly actions: ReadonlyArray<ActionName>
type CompanyConfigurations = {
readonly [K in CompanyName]: CompanyConfiguration
// A readonly literal object keeps the values at type level
const companyConfigurations = {
"dallbogg": {
name: "dallbogg",
actions: ["Quote"]
"wakam": {
name: "wakam",
actions: ["Quote", "Save"]
} as const
// We can check if it's compatible with a certain defined type (CompanyConfigurations)
type _Assert001 = Assert<CompatibleWith<typeof companyConfigurations, CompanyConfigurations>>
// We can know a compile type the exact values ("Quote")
type _Assert002 = Assert<Equals<"Quote", typeof companyConfigurations["dallbogg"]["actions"][number]>>
type _Assert003 = Assert<Equals<"Quote" | "Save", typeof companyConfigurations["wakam"]["actions"][number]>>
// By constraining the same value with a certain type the type checker discards the inferred types
const companyConfigurations_ : CompanyConfigurations = companyConfigurations
// Still compatible, no surprise here
type _Assert004 = Assert<Equals<typeof companyConfigurations_, CompanyConfigurations>>
// But we loose the values aka at compile time we don't know what kind of actions are supported by a certain company
type _Assert005 = AssertNot<Equals<"Quote", typeof companyConfigurations_["dallbogg"]["actions"][number]>>
type _Assert006 = AssertNot<Equals<"Quote" | "Save", typeof companyConfigurations_["wakam"]["actions"][number]>>
type _Assert007 = Assert<Equals<"Quote" | "Save" | "Emit", typeof companyConfigurations_["dallbogg"]["actions"][number]>>
type _Assert008 = Assert<Equals<"Quote" | "Save" | "Emit", typeof companyConfigurations_["wakam"]["actions"][number]>>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment