Check If an Object Implements an Interface at Runtime with Typescript

Check if an object implements an interface at runtime with TypeScript

No.

Currently, types are used only during development and compile time.
The type information is not translated in any way to the compiled
JavaScript code.

From https://stackoverflow.com/a/16016688/318557, as pointed out by @JasonEvans

There is an open issue since Jun 2015 about this in the TypeScript repo: https://github.com/microsoft/TypeScript/issues/3628

Interface type check with Typescript

You can achieve what you want without the instanceof keyword as you can write custom type guards now:

interface A {
member: string;
}

function instanceOfA(object: any): object is A {
return 'member' in object;
}

var a: any = {member: "foobar"};

if (instanceOfA(a)) {
alert(a.member);
}

Lots of Members

If you need to check a lot of members to determine whether an object matches your type, you could instead add a discriminator. The below is the most basic example, and requires you to manage your own discriminators... you'd need to get deeper into the patterns to ensure you avoid duplicate discriminators.

interface A {
discriminator: 'I-AM-A';
member: string;
}

function instanceOfA(object: any): object is A {
return object.discriminator === 'I-AM-A';
}

var a: any = {discriminator: 'I-AM-A', member: "foobar"};

if (instanceOfA(a)) {
alert(a.member);
}

Detect whether object implement interface in TypeScript dynamically

Yes. Now you can do this, using an enhanced version of the TypeScript compiler that allows you to know which interface implements each class of your application. This version of the compiler stores all types information until runtime, and links these information to actual constructors. For example, you can write something like the following:

function implementsInterface(object: Object, target: Interface) {
const objClass: Class = object.constructor && object.constructor.getClass();
if (objClass && objClass.implements) {
let found = false;
for (let base of objClass.implements) {
let found = interfaceExtends(base, target);
if (found) {
return true;
}
}
}
return false;
}

// recursive interface inheritance check
function interfaceExtends(i: Interface, target: Interface) {
if (i === target) {
return true;
}
if (i.extends) {
let found = false;
for (let base of i.extends) {
// do a recursive check on base interface...
found = interfaceExtends(base, target);
if (found) {
return true;
}
}
}
return false;
}

You can find a full working example that suits your needs here

Typescript check object by type or interface at runtime with typeguards in 2020+

TypeScript's type system is erased when compiled to JavaScript. That implies any effort to use the standard tsc compiler by itself to generate runtime type guards from type or interface definitions will not succeed; there's nothing of these definitions left at runtime for you to use. So ofType<T>() cannot be implemented.

So what can you do?


If you're willing to use some other compilation step in your build system, you can write or use a transformer that makes type guards for you from these definitions before they are erased. For example, typescript-is will do this.


Or you could use class definitions instead; this makes checking easy at runtime (just use instanceof) but the hard part is deserializing JSON into a class instance and catching errors upon deserialization without writing this yourself manually. All this does is move your problem from implementing ofType<Book>(someObj) to implementing myDeserializerFunction(Book, someObj) where Book is a class constructor.

Here at least you can use decorators and class metadata to generate the code needed for programmatic deserialization. You can write this yourself, or use an existing library such as json2typescript.


Finally, you might decide to start with the type guards and let TypeScript infer your type definitions from them. That is, instead of defining Book and hoping to get a type guard bookGuard() from it, you write the type guard bookGuard() and define Book in terms of typeof bookGuard.

This type guard could be built by composing existing simpler type guards together, so it looks more like a declarative type definition than a data-checking function. You can write this yourself, or use an existing library such as io-ts or zod.

For this approach, it's instructive to look at how one might write such a library. Here's one possible implementation:

export type Guard<T> = (x: any) => x is T;
export type Guarded<T extends Guard<any>> = T extends Guard<infer V> ? V : never;
const primitiveGuard = <T>(typeOf: string) => (x: any): x is T => typeof x === typeOf;
export const gString = primitiveGuard<string>("string");
export const gNumber = primitiveGuard<number>("number");
export const gBoolean = primitiveGuard<boolean>("boolean");
export const gNull = (x: any): x is null => x === null;
export const gObject =
<T extends object>(propGuardObj: { [K in keyof T]: Guard<T[K]> }) =>
(x: any): x is T => typeof x === "object" && x !== null &&
(Object.keys(propGuardObj) as Array<keyof T>).
every(k => (k in x) && propGuardObj[k](x[k]));
export const gArray =
<T>(elemGuard: Guard<T>) => (x: any): x is Array<T> => Array.isArray(x) &&
x.every(el => elemGuard(el));
export const gUnion = <T, U>(tGuard: Guard<T>, uGuard: Guard<U>) =>
(x: any): x is T | U => tGuard(x) || uGuard(x);

Here we are exporting a few type guards and functions which compose existing type guards. The gString(), gNumber(), gBoolean(), and gNull() functions are just type guards, while gObject(), gArray(), and gUnion() take existing type guards to make new type guards out of them. You can see how gObject() takes an object full of type guard properties and makes a new type guard where each property is checked against the corresponding guard. You could add other composition functions like gIntersection() or gPartial(), but the ones here are enough for your example.

Now your Book and Writer definitions look like this (assume the above has been imported as namespace G):

const _gWriter = G.gObject({
name: G.gString,
age: G.gNumber,
});
interface Writer extends G.Guarded<typeof _gWriter> { }
const gWriter: G.Guard<Writer> = _gWriter;

const _gBook = G.gObject({
id: G.gNumber,
name: G.gString,
tags: G.gUnion(G.gArray(G.gString), G.gNull),
writers: G.gArray(gWriter)
})
interface Book extends G.Guarded<typeof _gBook> { }
const gBook: G.Guard<Book> = _gBook;

If you squint at that you'll see that it's analogous to your example Writer and Book definitions. But in our case the fundamental objects are type guards gWriter and gBook and the types Writer and Book are derived from them. And then you can use gBook directly instead of the non-existent ofType<Book>():

const book = JSON.parse('{"id":1,"name":"Avangers","tags":["marvel","fun"],' +
'"writers":[{"name":"Max","age":25},{"name":"Max","age":25}]}');

if (gBook(book)) {
console.log(book.name.toUpperCase() + "!"); // AVANGERS!
}

Okay, hope that helps; good luck!

Playground link to code

TypeScript - Check if Class implements an Interface

Unlike classes, interfaces exist only at compile-time, they are not included into the resulting JavaScript, so you cannot do an instanceof check.

You could make IWalkingAnimal a subclass of Animal (and use instanceof), or you could check if the object in question has a walk method:

if (animal['walk']) {}

You can wrap this in a user defined type guard (so that the compiler can narrow the type when used in an if statement, just like with instanceof).

/**
* User Defined Type Guard!
*/
function canWalk(arg: Animal): arg is IWalkingAnimal {
return (arg as IWalkingAnimal).walk !== undefined;
}

private moveAnimal(animal: Animal) {
if (canWalk(animal)) {
animal.walk(); // compiler knows it can walk now
}
}

How to determine if a type implements an interface with C# reflection

You have a few choices:

  1. typeof(IMyInterface).IsAssignableFrom(typeof(MyType))
  2. typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface))
  3. With C# 6 you can use typeof(MyType).GetInterface(nameof(IMyInterface)) != null

For a generic interface, it’s a bit different.

typeof(MyType).GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMyInterface<>))


Related Topics



Leave a reply



Submit