Break down the process of declaring and checking TREE
to avoid circular dependencies. First, declare the elements:
type Element = null | { parent: keyof typeof TREE };
const TREE = {
'a': null,
'b': { parent: 'a' },
} as const;
Then proceed with the check:
const check: Record<string, Element> = TREE; // successful
This separation eliminates the circular nature as the type of TREE
solely depends on its initializer. If you were using the satisfies operator to maintain literal types for parent
properties in TREE
, consider using a const
assertion instead.
The check
const check: Record<string, Element> = TREE
will validate the assignment based on compatibility. Any non-
Element
properties in
TREE
will result in an error:
const TREE = {
'a': null,
'b': { parent: 'c' }, // <-- 'c'
} as const;
const check: Record<string, Element> = TREE; // error!
// ~~~~~
// Type '"c"' is not assignable to type '"a" | "b"'.
Though the error location may not be ideal, it clarifies the issue at hand.
Check out the code on Playground