foundry-vtt-types
foundry-vtt-types copied to clipboard
Audit all usages of common footgun types like `object`
object is the wrong type in 99% of cases because it includes all functions and all arrays. It has some limited usage in complex scenarios, mostly to prevent an index signature but that only matters when the base constraint is used or in other similarly niche scenarios.
Even when any object, any array, or any function is truly meant it's more self documenting to say Record<string, unknown> | Record<number, unknown> | (...args: any[]) => any. If this is a common situation then helper types could shorten it.
Similar footgun types include, but are not limited to:
{}; this is not an empty object, it instead includes numbers, strings, arrays, literally everything butnullandundefined.Record<string, any>; this includes plain objects, arrays, and functions. This probably is meant to beRecord<string, unknown>which is only plain objects.Record<string | number, T>this doesn't include arrays. UseRecord<string, T> | Record<number, T>for that.Record<any, T>this only includes objects.Record<never, T>- this probably was supposed to beRecord<string, never>which is the closest type to an object with no properties.Record<never, T>allows any object.Record<string, unknown>- despite only being for plain objects, this has the footgun that interfaces can't be assigned to it. This is somewhat illogical if they already have properties. This can be rectified on the user's end by merging in the index signature. This also has the second footgun of not allowing readonly properties.- In certain contexts
Promiseis a arguably a footgun because it disallows synchronous functions to be assigned to it. This is mostly only a problem within callbacks or object properties. anyis also a footgun in many contexts. In some cases it makes sense butanyin many contexts can be replaced withunknownorneveror so on.
Therefore the best constraint to use for most objects would be { readonly [K: string]: T } unless mutability is actively desired.