Is there a way to test if a value is an instance of a Record type in TypeScript? I want a case that properly distinguishes when the variable could potentially also be an array.
function(a: Record<string,string>|string[]) {
if( a instanceof Record ) {
do_stuff( a.key )
}
}
I know this is problematic in JavaScript because both of my types are objects, thus typeof(a) == "object" in both cases. I'm hoping there's perhaps a special TypeScript way to accomplish this.
I understand the Record type doesn't really exist at runtime, but the example should clarify what I'm trying to do. It's also important that the test properly informs TypeScript of the narrowed type, so that a.key doesn't produce an error.
As per the documentation, a Record<K, V> is an object whose keys are K and values are V. A "true" Record<string, string> doesn't exist because of the prototype chain, which causes objects to inherit e.g. a .toString() method. But taking into consideration the complete set of inherited properties would be cumbersome (related discussion on the TS GitHub), so it's clearest to think of the Record type working with an object's own properties:
// Allowed:
const foo: Record<string, string> = { bar: "bar" }
// Even though functions aren't a subtype of string:
type inheritedToString = typeof foo.toString
// ~~~~~~~~~~~~~~~~~
// inheritedToString = () => string
This means you'll most likely get far enough by combining one or many of the ways of iterating over properties in an object with TypeScript's type predicates:
function isStringRecord(obj: unknown): obj is Record<string, string> {
if (typeof obj !== "object")
return false
if (Array.isArray(obj))
return false
if (Object.getOwnPropertySymbols(obj).length > 0)
return false
return Object.getOwnPropertyNames(obj)
.every(prop => typeof obj[prop] === "string")
}
Now you'll have:
const foo = { bar: "bar" } as unknown
if (isStringRecord(foo)) {
foo // foo: Record<string, string>
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With