If you're looking for a more generic-constraint version of PartialOrFunction
that was mentioned in the comments, here's what you can do.
Your PartialOrFunction<T>
is essentially a specialized instance of something I like to call DefaultProperty<T, D>
. This concept involves taking an object type T
without an index signature and adding a "default" property of type D
to it. Unlike a string index signature that requires all properties in T
to be assignable to
D</code, this approach differs. Unfortunately, TypeScript lacks support for such operations currently.</p>
<p>In order to achieve that functionality, you would ideally want to negate types to exclude <code>keyof T
from
string</code, which isn't possible at the moment. Therefore, a makeshift solution could look something like:</p>
<pre><code>type MakeshiftDefaultProperty<T, D> = T & {[k: string]: D | T[keyof T]}
While this workaround may not be perfect as it allows unwanted properties, it might suffice depending on your needs.
To address this limitation, we can introduce a type
VerifyDefaultProperty<T, D, C>
that validates a candidate variable
C</code against the desired structure of <code>DefaultProperty<T, D>
.
type VerifyDefaultProperty<T extends object, D, C> =
{ [K in keyof C]: K extends keyof T ? T[K] : D }
By using this approach, you can ensure that a given set of properties adheres to the intended structure.
Similarly, to handle situations where TypeScript doesn't natively support PartialOrFunction
, you can create a modified version called
VerifyPartialOrFunction<T, C>
that conforms to similar rules.
type VerifyPartialOrFunction<T, C> = VerifyDefaultProperty<
{ [K in keyof T]?: T[K] | ((params?: Partial<T>) => string) },
((params?: Partial<T>) => string),
C
>;
Furthermore, by implementing a curried helper function like verifyPartialOrFunction
, you can streamline the validation process while ensuring type safety.
const verifyPartialOrFunction = <T>() =>
<C>(x: C & VerifyPartialOrFunction<T, C>): C =>
x;
These mechanisms allow you to validate objects against predefined structures effectively, offering flexibility within TypeScript.
As illustrated, handling these scenarios may involve intricate type manipulations outside standard TypeScript capabilities. For internal use cases within your codebase, consider utilizing broader types alongside type assertions when necessary.
I hope these insights provide clarity on how to navigate complex typing scenarios within TypeScript. Feel free to explore the provided code snippets for practical implementations.