631

This question is the direct analogon to Class type check with TypeScript

I need to find out at runtime if a variable of type any implements an interface. Here's my code:

interface A{
    member:string;
}

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

if(a instanceof A) alert(a.member);

If you enter this code in the typescript playground, the last line will be marked as an error, "The name A does not exist in the current scope". But that isn't true, the name does exist in the current scope. I can even change the variable declaration to var a:A={member:"foobar"}; without complaints from the editor. After browsing the web and finding the other question on SO I changed the interface to a class but then I can't use object literals to create instances.

I wondered how the type A could vanish like that but a look at the generated javascript explains the problem:

var a = {
    member: "foobar"
};
if(a instanceof A) {
    alert(a.member);
}

There is no representation of A as an interface, therefore no runtime type checks are possible.

I understand that javascript as a dynamic language has no concept of interfaces. Is there any way to type check for interfaces?

The typescript playground's autocompletion reveals that typescript even offers a method implements. How can I use it ?

Dharman
  • 30,962
  • 25
  • 85
  • 135
lhk
  • 27,458
  • 30
  • 122
  • 201
  • 7
    JavaScript has no concept of interfaces, but that isn't because it is a dynamic language. It's because interfaces aren't implemented yet. – trusktr Feb 16 '17 at 01:53
  • 1
    Yes, but you can use class instead interface. See [this](https://stackoverflow.com/a/53814012/4604351) example. – Alexey Baranoshnikov Dec 17 '18 at 11:22
  • 1
    Apparently not in 2017. Super relevant question now. – doublejosh Mar 26 '20 at 05:17
  • 9
    Coming from a C# background, all the solutions at the day of writing are terrible! It involves copy duplicating and compromising code readability. – Brackets Dec 16 '20 at 15:47
  • Please vote for better Outline/IntelliSense support at [vscode/issues/157461](https://github.com/microsoft/vscode/issues/157461) and [TypeScript/issues/10752](https://github.com/microsoft/TypeScript/issues/10752) to answer this already at coding time (and match [Webstorm](https://www.jetbrains.com/help/webstorm/viewing-structure-and-hierarchy-of-the-source-code.html) ) – cachius Sep 06 '22 at 16:34

28 Answers28

511

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);
}
John Miller
  • 388
  • 2
  • 8
  • 23
Fenton
  • 241,084
  • 71
  • 387
  • 401
  • 209
    "There is no way to runtime check an interface." There is, they just haven't implemented it yet for whatever reason. – trusktr Feb 16 '17 at 01:54
  • @trusktr amended so the sentence can be taken out of context. – Fenton Feb 17 '17 at 06:33
  • 84
    And if the interface has 100 members, you need to check all 100? Foobar. – Krisztián Balla Nov 24 '17 at 10:43
  • 14
    You could add a discriminator to your object rather than check all 100... – Fenton Nov 24 '17 at 11:03
  • 40
    this discriminator paradigm (as written here) doesn't support extending interfaces. A derived interface would return false if checking if it is an instanceOf a base interface. – Aaron May 17 '18 at 15:20
  • @Aaron I don't think I understand your point as the custom type guard doesn't use `intanceOf`. It uses the discriminator - and that has to be present and identical on all implementations of the interface, or of interfaces that extend it. – Fenton May 18 '18 at 09:22
  • 3
    @Fenton Perhaps I don't know enough about this, but suppose you had an interface B that extends interface A, you'd want `isInstanceOfA(instantiatedB)` to return true, but you'd want `isInstanceOfB(instantiatedA)` to return false. For the latter to occur, wouldn't the discriminator of B have to not be 'I-AM-A'? – Aaron May 18 '18 at 17:12
  • This is the opposite of your original question, but in this case you would need to discriminate on a different member for `B`, i.e. it would need `discriminator: 'I-AM-A'` to satisfy extending `A` and it would also need some other property `bDiscriminator: 'I-AM-B'`. This isn't the only way to solve the problem - and I'm sure it's not the most graceful. – Fenton May 21 '18 at 06:50
  • 1
    @Fenton Oh I see, you would use a completely different member as a discriminator for each interface. the `discriminator: 'I-AM-A'` fooled me into thinking that each interface would just provide a unique value in the discriminator member. So I thought interface B would have `discriminator: 'I-AM-B'` which would have made `isInstanceOfA(b)` return false. – Aaron May 21 '18 at 18:25
  • @Aaron that's right - everything that extends interface A _must_ have `I-AM-A` in `discriminator` as it is the only allowed value. If they want their own discriminator it must be another property. – Fenton May 22 '18 at 07:08
  • any good reason for using `thing is Type` syntax ? Seems to work fine with just using `boolean` – nikksan Dec 30 '18 at 14:14
  • 1
    `thing is Type` guarantees the type will be narrowed, the compiler can infer this _in some cases_ without the function being a custom type guard, but in many cases it doesn't. For example a `A | any` type will still be `any` after the `boolean` version, but it will be an `A` with `thing is A`. – Fenton Jan 16 '19 at 11:22
  • @trusktr There is no way to runtime check an interface. Not only because browsers didn't implement a check but, most important, because interfaces make absolutely no sense in JavaScript. They are not part of the spec and they, at best, will only be implemented partially to help developers. – JP de la Torre Feb 07 '19 at 20:12
  • 1
    @JPdelaTorre By "there is a way" I meant: TypeScript would have to implement runtime output, and the result would be some duck-type checks. To me that counts as a way (that isn't implemented yet). It may be out of the scope TypeScript team desires to have though. – trusktr Feb 07 '19 at 23:45
  • @trusktr Generalizing duck typing would be impossible without checking for every member the interface has and, as Jenny O'Reilly put it above, "if the interface has 100 members, you need to check all 100?". Adding discriminators seems like the right idea, but they can't be added dynamically on every case needed without breaking in many cases. I think not having a feature is better than having a half-assed solution that breaks regularly. – JP de la Torre Feb 08 '19 at 14:24
  • I believe the feature should be opt-in, inside of the TypeScript source where you need it. That syntax could be `if (a is A)` with an `is` keyword or similar. There would obviously be a fast-path for objects generated from the same TypeScript source. But of course, making your own guard can be better in cases where there's too many props to check. It would be a matter of finding a balance, and knowing about your use cases. I wouldn't say the feature is completely bad, or completely good. It depends on the case. I'd like the option of making the choice to use such a feature when it makes sense. – trusktr Feb 08 '19 at 19:11
  • @JPdelaTorre Forgot to mention you in the last comment. ^ Additionally, I'm willing to place lots of money betting that the performance hit from checking 100 props is imperceivable by an end user in a large majority of cases. Where it could have impact is in graphical code running at 60fps, but lots of the time business logic can take up to 100ms to complete, and this is still fine. Handling the user experience is key (f.e. place a seperate-thread CSS loading spinner on the page while performing the logic at strategic times, and block user interaction during those times. Users will wait). – trusktr Feb 08 '19 at 19:18
  • In my experiences, bottlenecks in rendering are usually due to WebGL structure. I do LOTS of things in my code that deoptimize the JS engine, in order to gain useful features like private and protected members in my runtime JS code, but these performance hits are still a *tiny* fraction of what WebGL rendering can cost. – trusktr Feb 08 '19 at 19:22
  • what?! then we should put the value on each object we create?! it's really not an answer – Hamed Zakery Miab May 23 '19 at 12:59
  • 1
    @HamedZakeryMiab you don't have to! You _can_ do that if you want to use discriminated unions. You can avoid doing it if you can write a custom type guard that answers your question (does this object have a member with the appropriate name and type). – Fenton Jun 11 '19 at 10:51
  • How does this work with minification? What happens if the minifier offuscates the `member` property? – Sébastien Tromp Jun 26 '19 at 09:53
  • 1
    @SébastienTromp I just tried a couple of examples and they seem to be `in` aware (so if they detect an `in` they preserve names). You'll need to make sure you are using an up-to-date minifier, but it should work. I imagine minifiers have a similar challenge with `hasOwnProperty` and similar cases. – Fenton Jul 02 '19 at 17:56
  • 3
    This looks like a bad habbit. Still no better solution? – Oswald Jan 23 '20 at 03:25
  • Also, do note that checking if a member exists is not the same as checking if the member has the expected type -- if I have a property `foo` that the interface requires to be a boolean, but I pass in `{ foo: "FUBAR" }`, then the simple `in` check would erroneously tell you that the argument implements the interface. In the case of incorrect property types, the code example above would ensure your type-checking was wrong, because Typescript would think that `foo` was a boolean when it was actually a `string`. – Robert Fischer Jul 23 '20 at 02:03
  • 3
    Nothing more than a hack. – Ash Aug 07 '20 at 09:50
  • `instanceOfA(null)` or `instanceOfA(5)` or any non-object value throws an exception – Mingwei Samuel Aug 07 '20 at 16:09
  • What if the two interfaces contains the same member setup? – PatricNox Oct 26 '20 at 13:00
  • @PatricNox don't complicate it, they need to differ something, otherwise they wouldn't be two interfaces. – giovannipds Dec 10 '20 at 19:25
  • 56
    Can't believe we're in 2020 and there's no better way of doing this... =/ – giovannipds Dec 10 '20 at 19:26
  • Sadly, this is a legacy of underlying runtime. Hopefully one day TS will run on its own strictly typed VM and such a basic operation as type check won't be a big bummer – ruX Jul 28 '21 at 11:29
  • Is this still the recommended way as of now in 2021? I mean this works but has its own burdens. For example, in my case, I have two interfaces `A` and `B`, after adding a discriminator, I have to remove it before passing an instance of the interface to an api which doesn't understand the discriminator field. – dragonfly02 Sep 13 '21 at 05:48
  • **Warning!** ``instanceOfA("string")`` causes an exception! BTW, what does the syntax `: object is A {` mean? Shouldn't the colon be followed by the return type, so: `: boolean {`? I added [a solution without these problems](https://stackoverflow.com/a/71248398/2484903). – Jack Miller Feb 24 '22 at 07:22
  • 2
    what is the point of typing everything if you need to check an interface with quotes ? Oo – alexino2 Apr 15 '22 at 03:40
  • In 2022 it's still like in 1996, we have to iterate an object to see if it has a property. None of the redundant posts here check for "is a" but instead "has a" which can fail spectacularly. Ultimately they're all just `typeof thing != 'undefined'`. At least this answer has IMHO the nicest syntax with `if 'member' in object`. – Maxim Paperno Sep 29 '22 at 07:24
  • 2023 now and still no solution for this ? Typescript has "type" in it, what a scam :) – daniel.rna Feb 13 '23 at 13:45
  • 1
    I wonder how/why `object is A` is used here instead of `boolean`? – Yuriy Galanter Feb 14 '23 at 21:26
  • 1
    @YuriyGalanter `object is A` tells the TypeScript compiler that this is a type guard, and it changes the type of the object inside blocks such as `if (isInstanceOfA(obj))`. So if you hover over your object after that if-statement, you'll see the compiler says it's an "A" not some other type. With a return type of boolean, it won't narrow the type. – Fenton Mar 01 '23 at 09:23
  • 3
    It looks like it's 2023 and there isn't a better way to do this... – Ricardo Araque Apr 13 '23 at 19:39
155

In TypeScript 1.6, user-defined type guard will do the job.

interface Foo {
    fooProperty: string;
}

interface Bar {
    barProperty: string;
}

function isFoo(object: any): object is Foo {
    return 'fooProperty' in object;
}

let object: Foo | Bar;

if (isFoo(object)) {
    // `object` has type `Foo`.
    object.fooProperty;
} else {
    // `object` has type `Bar`.
    object.barProperty;
}

And just as Joe Yang mentioned: since TypeScript 2.0, you can even take the advantage of tagged union type.

interface Foo {
    type: 'foo';
    fooProperty: string;
}

interface Bar {
    type: 'bar';
    barProperty: number;
}

let object: Foo | Bar;

// You will see errors if `strictNullChecks` is enabled.
if (object.type === 'foo') {
    // object has type `Foo`.
    object.fooProperty;
} else {
    // object has type `Bar`.
    object.barProperty;
}

And it works with switch too.

Egel
  • 1,796
  • 2
  • 24
  • 35
vilicvane
  • 11,625
  • 3
  • 22
  • 27
  • 1
    This looks rather curious. Apparently there is some kind of meta-information available. Why expose it with this type-guard syntax. Due to which constraints does "object is interface" next to a function work, as opposed to isinstanceof ? More precisely, could you use "object is interface" in the if statements directly ? But in any case, very interesting syntax, +1 from me. – lhk Dec 25 '15 at 08:36
  • 2
    @lhk No there isn't such a statement, it's more like a special type that tells how should a type be narrowed inside conditional branches. Due to the "scope" of TypeScript, I believe there won't be such a statement even in the future. Another different between `object is type` and `object instanceof class` is that, type in TypeScript is structural, it cares only the "shape" instead of where did an object get the shape from: a plain object or an instance of a class, it doesn't matter. – vilicvane Dec 26 '15 at 09:29
  • 2
    Just to clear a misconception this answer can create: there's no meta information to deduct object type or its interface during runtime. – mostruash Mar 30 '16 at 22:09
  • 1
    @mostruash Yep, the second half of the answer won't work at runtime even though it compiles. – trusktr Feb 16 '17 at 01:58
  • 6
    Oh, but, this must assume that at runtime these objects will have been created with a `type` property. In that case it works. That example doesn't show this fact. – trusktr Feb 16 '17 at 02:00
  • This is just using a discriminator based on a string. – dessalines Apr 12 '19 at 19:05
71

How about User-Defined Type Guards? https://www.typescriptlang.org/docs/handbook/advanced-types.html

interface Bird {
    fly();
    layEggs();
}

interface Fish {
    swim();
    layEggs();
}

function isFish(pet: Fish | Bird): pet is Fish { //magic happens here
    return (<Fish>pet).swim !== undefined;
}

// Both calls to 'swim' and 'fly' are now okay.

if (isFish(pet)) {
    pet.swim();
}
else {
    pet.fly();
}
Caleb Macdonald Black
  • 1,494
  • 12
  • 17
  • 3
    This is my favorite answer - similar to http://stackoverflow.com/a/33733258/469777 but without magic strings that may break due to things like minification. – Stafford Williams Sep 26 '16 at 09:17
  • 3
    This did not work for me for some reason but `(pet as Fish).swim !== undefined;` did. – CyberMew Jul 09 '19 at 03:05
  • 5
    What happens, when you add `swim();` to Bird, because you got a pet duck? Every pet would be recognised as fish, wouldn't it? – Kayz Jul 15 '20 at 15:52
  • 4
    @Kayz I guess when you use `isFish`, your code isn't really concerned with whether or not the object falls into the arbitrary fish category, you're more concerned whether or not your object supports swim operations. Perhaps a better function name might reflect this such as `isAquatic` or something. This sort of method for identifying object type is called duck typing and you can look more into that if you want. But in short, if a duck can swim then is a fish and we have a naming problem to solve. https://en.wikipedia.org/wiki/Duck_typing – Caleb Macdonald Black Jul 16 '20 at 00:22
  • 2
    What's the point of ability to pass Fish or Bird, if "pet is Fish"? This is terrible readability! – Brackets Dec 16 '20 at 14:45
  • @Brackets I'm looking into the type guard documentation again as it's been some time since I've worked with Typescript. In the documentation, it says "A type guard is some expression that performs a runtime check that guarantees the type in some scope". "pet is Fish" is the type guard here and the expression in the return statement of the function determines the result of the runtime check. My answer is simply relaying information from the official documentation. Personally, I agree somewhat that type guards are perhaps not intuitive without prior experience. I guess it is what it is. – Caleb Macdonald Black Dec 17 '20 at 04:27
59

typescript 2.0 introduce tagged union

Typescript 2.0 features

interface Square {
    kind: "square";
    size: number;
}

interface Rectangle {
    kind: "rectangle";
    width: number;
    height: number;
}

interface Circle {
    kind: "circle";
    radius: number;
}

type Shape = Square | Rectangle | Circle;

function area(s: Shape) {
    // In the following switch statement, the type of s is narrowed in each case clause
    // according to the value of the discriminant property, thus allowing the other properties
    // of that variant to be accessed without a type assertion.
    switch (s.kind) {
        case "square": return s.size * s.size;
        case "rectangle": return s.width * s.height;
        case "circle": return Math.PI * s.radius * s.radius;
    }
}
Joe Yang
  • 1,615
  • 14
  • 10
19

It's now possible, I just released an enhanced version of the TypeScript compiler that provides full reflection capabilities. You can instantiate classes from their metadata objects, retrieve metadata from class constructors and inspect interface/classes at runtime. You can check it out here

Usage example:

In one of your typescript files, create an interface and a class that implements it like the following:

interface MyInterface {
    doSomething(what: string): number;
}

class MyClass implements MyInterface {
    counter = 0;

    doSomething(what: string): number {
        console.log('Doing ' + what);
        return this.counter++;
    }
}

now let's print some the list of implemented interfaces.

for (let classInterface of MyClass.getClass().implements) {
    console.log('Implemented interface: ' + classInterface.name)
}

compile with reflec-ts and launch it:

$ node main.js
Implemented interface: MyInterface
Member name: counter - member kind: number
Member name: doSomething - member kind: function

See reflection.d.ts for Interface meta-type details.

UPDATE: You can find a full working example here

PEHLAJ
  • 9,980
  • 9
  • 41
  • 53
pcan
  • 893
  • 11
  • 24
  • 14
    downvoted cos I thought this was stupid, but then paused for a second, looked at your github page and saw it was kept up to date and well documented so upvoted instead :-) I still can't justify using it myself right now just for `implements` but wanted to recognize your commitment and didn't want to be mean :-) – Simon_Weaver Aug 23 '16 at 09:34
  • 5
    Actually, the main purpose I see of this reflection features is to create better IoC frameworks like the ones the Java world already has since long time (Spring is the first and most important one). I firmly believe that TypeScript can become one of the best development tools of the future and reflection is one of the features it really needs. – pcan Aug 24 '16 at 10:11
  • 7
    ...uh, so what, we have to roll these compiler "enhancements" into any future build of Typescript? This is effectively a fork of Typescript, not Typescript itself, right? If so, this isn't a feasible long-term solution. – dudewad Dec 07 '16 at 21:01
  • 2
    @dudewad as said in many other topics, this is a temporary solution. We are waiting compiler extensibility through transformers. Please see related issues in the official TypeScript repo. Furthermore, all the widely adopted strong-typed languages have reflection, and I think TypeScript should have it too. And like me, many other users think so. – pcan Dec 07 '16 at 21:28
  • yeah its not that I don't agree -- I want this too. Just, spinning up a custom compiler... doesnt that mean the next patch of Typescript needs to get ported? If you're upkeeping it then kudos. Just seems like a lot of work. Not knocking it. – dudewad Dec 07 '16 at 22:23
  • 1
    I downvoted this since it's not an answer about typescript. You've basically promoting your own language which can be nice, can be powerful, can be awesome but it's in any case not a typescript. – shabunc Jun 03 '20 at 12:10
  • @shabunc it's your opinion. Typescript should be what community expects to be. As an open source project, the governance model should follow (at least loosely) the suggestion from the community. There are LOTS of old open issues that ask for reflection/type inspection, and even if the team states it's "out of scope", they should realize that EVERY SINGLE language that comes out nowadays has at least some minimal reflection capability. Furthermore, if you read my notes, the project is on standby, waiting for official Plugin support (people is asking this for years, too, but no answer yet) – pcan Jun 04 '20 at 08:14
  • @pcan of course it’s my opinion, also, it’s a fact: feature introduced in a forked project doesn’t help someone who looks for an answer for that particular project. One thing is to inform in comments that one forked a project and here’s how the fork is better, the other is to present it as an answer. Imagine one will ask a question about python and I’m like - the answer is to use my fork of python - there are some features in my fork that community love to have! – shabunc Jun 04 '20 at 08:19
  • 2
    and this is exactly the purpose of a proof of concept: to demonstrate to people that things CAN be done. The question states: "I understand that javascript as a dynamic language has no concept of interfaces. Is there any way to type check for interfaces?" The answer is: NO with no modifications/improvement, but YES if we have a way to extend/improve the language & compiler. The question is: who decides the changes? but this is another topic. – pcan Jun 04 '20 at 08:28
19

Type guards in Typescript:

TS has type guards for this purpose. They define it in the following manner:

Some expression that performs a runtime check that guarantees the type in some scope.

This basically means that the TS compiler can narrow down the type to a more specific type when it has sufficient information. For example:

function foo (arg: number | string) {
    if (typeof arg === 'number') {
        // fine, type number has toFixed method
        arg.toFixed()
    } else {
        // Property 'toFixed' does not exist on type 'string'. Did you mean 'fixed'?
        arg.toFixed()
        // TSC can infer that the type is string because 
        // the possibility of type number is eliminated at the if statement
    }
}

To come back to your question, we can also apply this concept of type guards to objects in order to determine their type. To define a type guard for objects, we need to define a function whose return type is a type predicate. For example:

interface Dog {
    bark: () => void;
}

// The function isDog is a user defined type guard
// the return type: 'pet is Dog' is a type predicate, 
// it determines whether the object is a Dog
function isDog(pet: object): pet is Dog {
  return (pet as Dog).bark !== undefined;
}

const dog: any = {bark: () => {console.log('woof')}};

if (isDog(dog)) {
    // TS now knows that objects within this if statement are always type Dog
    // This is because the type guard isDog narrowed down the type to Dog
    dog.bark();
}
Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
17

Here's another option: the module ts-interface-builder provides a build-time tool that converts a TypeScript interface into a runtime descriptor, and ts-interface-checker can check if an object satisfies it.

For OP's example,

interface A {
  member: string;
}

You'd first run ts-interface-builder which produces a new concise file with a descriptor, say, foo-ti.ts, which you can use like this:

import fooDesc from './foo-ti.ts';
import {createCheckers} from "ts-interface-checker";
const {A} = createCheckers(fooDesc);

A.check({member: "hello"});           // OK
A.check({member: 17});                // Fails with ".member is not a string" 

You can create a one-liner type-guard function:

function isA(value: any): value is A { return A.test(value); }
DS.
  • 22,632
  • 6
  • 47
  • 54
13

Approaching 9 years since OP, and this problem remains. I really REALLY want to love Typescript. And usually I succeed. But its loopholes in type safety is a foul odor that my pinched nose can't block.

My goto solutions aren't perfect. But my opinion is they are better than most of the more commonly prescribed solutions. Discriminators have proven to be a bad practice because they limit scalability and defeat the purpose of type safety altogether. My 2 prettiest butt-ugly solutions are, in order:

Class Decorator: Recursively scans the typed object's members and computes a hash based on the symbol names. Associates the hash with the type name in a static KVP property. Include the type name in the hash calculation to mitigate risk of ambiguity with ancestors (happens with empty subclasses). Pros: It's proven to be the most trustworthy. It is also provides very strict enforcements. This is also similar to how other high-level languages natively implement polymorphism. Howbeit, the solution requires much further extension in order to be truly polymorphic. Cons: Anonymous/JSON objects have to be rehashed with every type check, since they have no type definitions to associate and statically cache. Excessive stack overhead results in significant performance bottlenecks in high load scenarios. Can be mitigated with IoC containers, but that can also be undesirable overhead for small apps with no other rationale. Also requires extra diligence to apply the decorator to every object requiring it.

Cloning: Very ugly, but can be beneficial with thoughtful strategies. Create a new instance of the typed object and reflexively copy the top-level member assignments from the anonymous object. Given a predetermined standard for passage, you can simultaneously check and clone-cast to types. Something akin to "tryParse" from other languages. Pros: In certain scenarios, resource overhead can be mitigated by immediately using the converted "test" instance. No additional diligence required for decorators. Large amount of flexibility tolerances. Cons: Memory leaks like a flour sifter. Without a "deep" clone, mutated references can break other components not anticipating the breach of encapsulation. Static caching not applicable, so operations are executed on each and every call--objects with high quantities of top-level members will impact performance. Developers who are new to Typescript will mistake you for a junior due to not understanding why you've written this kind of pattern.

All totalled: I don't buy the "JS doesn't support it" excuse for Typescript's nuances in polymorphism. Transpilers are absolutely appropriate for that purpose. To treat the wounds with salt: it comes from Microsoft. They've solved this same problem many years ago with great success: .Net Framework offered a robust Interop API for adopting backwards compatibility with COM and ActiveX. They didn't try to transpile to the older runtimes. That solution would have been much easier and less messy for a loose and interpreted language like JS...yet they cowered out with the fear of losing ground to other supersets. Using the very shortcomings in JS that was meant to be solved by TS, as a malformed basis for redefining static typed Object-Oriented principle is--well--nonsense. It smacks against the volumes of industry-leading documentation and specifications which have informed high-level software development for decades.

  • 12
    Consider adding code examples instead, it's easier to read small code samples with short explanations to the. – andnik Nov 17 '21 at 13:25
  • I can't believe @andnik that you dare comment on this answer from Anthony. It is useful and well articulated. – mikegross Oct 20 '22 at 10:14
  • :-) absolutely. – andnik Oct 20 '22 at 14:41
  • I'm perplexed as well.. with all the magic TypeScript is doing, even something so insane as how decorators work under the hood, how can something so simple as checking if an object is an interface be left out and even avoided???!?!?!??! I simply want to do `if (myObject is ICat) {...}` – TruMan1 Mar 07 '23 at 03:17
  • 1
    Think I'm gonna migrate to Kotlin because of this... – Mircea D. Mar 21 '23 at 11:10
11

I would like to point out that TypeScript does not provide a direct mechanism for dynamically testing whether an object implements a particular interface.

Instead, TypeScript code can use the JavaScript technique of checking whether an appropriate set of members are present on the object. For example:

var obj : any = new Foo();

if (obj.someInterfaceMethod) {
    ...
}
Daniel Ribeiro
  • 10,156
  • 12
  • 47
  • 79
  • 4
    what if you have a complex shape? you would not want to hardcode every single property at each level of depth – Tom Jul 04 '18 at 23:57
  • @Tom I guess you can pass (as a second parameter to the checker function) a run-time value or example/exemplar -- i.e. an object of the interface which you want. Then, instead of hard-coding code, you write any example of the interface which you want ... and write some one-time object-comparison code (using e.g. `for (element in obj) {}`) to verify that the two objects have the similar elements of similar types. – ChrisW May 08 '19 at 13:11
11

same as above where user-defined guards were used but this time with an arrow function predicate

interface A {
  member:string;
}

const check = (p: any): p is A => p.hasOwnProperty('member');

var foo: any = { member: "foobar" };
if (check(foo))
    alert(foo.member);
Dan Dohotaru
  • 2,809
  • 19
  • 15
11

In my opinion this is the best approach; attach a "Fubber" symbol to the interfaces. It is MUCH faster to write, MUCH faster for the JavaScript engine than a type guard, supports inheritance for interfaces and makes type guards easy to write if you need them.

This is the purpose for which ES6 has symbols.

Interface

// Notice there is no naming conflict, because interfaces are a *type*
export const IAnimal = Symbol("IAnimal"); 
export interface IAnimal {
  [IAnimal]: boolean; // the fubber
}

export const IDog = Symbol("IDog");
export interface IDog extends IAnimal {
  [IDog]: boolean;
}

export const IHound = Symbol("IDog");
export interface IHound extends IDog {
  // The fubber can also be typed as only 'true'; meaning it can't be disabled.
  [IDog]: true;
  [IHound]: boolean;
}

Class

import { IDog, IAnimal } from './interfaces';
class Dog implements IDog {
  // Multiple fubbers to handle inheritance:
  [IAnimal] = true;
  [IDog] = true;
}

class Hound extends Dog implements IHound {
  [IHound] = true;
}

Testing

This code can be put in a type guard if you want to help the TypeScript compiler.

import { IDog, IAnimal } from './interfaces';

let dog = new Dog();

if (dog instanceof Hound || dog[IHound]) {
  // false
}
if (dog[IAnimal]?) {
  // true
}

let houndDog = new Hound();

if (houndDog[IDog]) {
  // true
}

if (dog[IDog]?) {
  // it definitely is a dog
}

frodeborli
  • 1,537
  • 1
  • 21
  • 30
  • I use getter `get [ISymbol](){return true}` since it doesn't create a property for every instance. – Alexander Lonberg Feb 10 '22 at 20:19
  • @AlexanderLonberg Yeah; that works. Wonder how this would be optimized; in your case the engine would have to check the object first, then go to the prototype and invoke the getter function. In my case there may be a lot of duplication. In either case, the javascript engine could optimize away the cost. – frodeborli Feb 10 '22 at 21:22
  • Oh, a [little slow](https://jsben.ch/FujlG) – Alexander Lonberg Feb 10 '22 at 22:44
  • @AlexanderLonberg Thank you, nice to have some actual numbers to go with. Both Firefox and Chrome appears to optimize away the cost of invoking a static getter method. Those numbers would have been very different a few years ago I believe. – frodeborli Feb 14 '22 at 22:35
  • ditto Edge and Safari, tested on both (mac) desktop and iOS. this is the best answer. – Peter S Magnusson Nov 29 '22 at 00:02
7

TypeGuards

interface MyInterfaced {
    x: number
}

function isMyInterfaced(arg: any): arg is MyInterfaced {
    return arg.x !== undefined;
}

if (isMyInterfaced(obj)) {
    (obj as MyInterfaced ).x;
}
Dmitry Matveev
  • 5,320
  • 1
  • 32
  • 43
  • 2
    the "arg is MyInterfaced" is an interesting annotation. What happens if that fails ? Looks like a compile time interface check - which would be just what I wanted in the first place. But if the compiler checks the parameters, why have a function body at all. And if such a check is possible, why move it to a separate function. – lhk Jun 28 '17 at 10:50
  • 3
    @lhk just read typescript documentation about type guards... https://www.typescriptlang.org/docs/handbook/advanced-types.html – Dmitry Matveev Jun 28 '17 at 21:13
  • 1
    @DmitryMatveev orrr...just answer the perfectly reasonable question, rather than pointing to documentation that doesn't? – Ash Aug 07 '20 at 09:53
  • @lhk Not sure if you still had a question about this, but in any case, I'll try _actually_ answering it. You're right in that it is a compile-time check. The `arg is MyInterfaced` bit tells the compiler: "If a branch calls this function and the result is true, accept all further use of the object that was tested to be of type MyInterfaced". What was probably causing you confusion can be highlighted with the key bit in that statement which is, "if the result is true". Unfortunately that is upto the developer to determine what _constitutes_ a `MyInterfaced`. – Ash Aug 07 '20 at 10:07
  • I say "unfortunately" because for the purpose of generally determining whether any given object is of any given interface type, this approach is less that useless. – Ash Aug 07 '20 at 10:09
7

Based on Fenton's answer, here's my implementation of a function to verify if a given object has the keys an interface has, both fully or partially.

Depending on your use case, you may also need to check the types of each of the interface's properties. The code below doesn't do that.

function implementsTKeys<T>(obj: any, keys: (keyof T)[]): obj is T {
    if (!obj || !Array.isArray(keys)) {
        return false;
    }

    const implementKeys = keys.reduce((impl, key) => impl && key in obj, true);

    return implementKeys;
}

Example of usage:

interface A {
    propOfA: string;
    methodOfA: Function;
}

let objectA: any = { propOfA: '' };

// Check if objectA partially implements A
let implementsA = implementsTKeys<A>(objectA, ['propOfA']);

console.log(implementsA); // true

objectA.methodOfA = () => true;

// Check if objectA fully implements A
implementsA = implementsTKeys<A>(objectA, ['propOfA', 'methodOfA']);

console.log(implementsA); // true

objectA = {};

// Check again if objectA fully implements A
implementsA = implementsTKeys<A>(objectA, ['propOfA', 'methodOfA']);

console.log(implementsA); // false, as objectA now is an empty object
aledpardo
  • 761
  • 9
  • 19
6

I found an example from @progress/kendo-data-query in file filter-descriptor.interface.d.ts

Checker

declare const isCompositeFilterDescriptor: (source: FilterDescriptor | CompositeFilterDescriptor) => source is CompositeFilterDescriptor;

Example usage

const filters: Array<FilterDescriptor | CompositeFilterDescriptor> = filter.filters;

filters.forEach((element: FilterDescriptor | CompositeFilterDescriptor) => {
    if (isCompositeFilterDescriptor(element)) {
        // element type is CompositeFilterDescriptor
    } else {
        // element type is FilterDescriptor
    }
});
xinthose
  • 3,213
  • 3
  • 40
  • 59
5

I knew I'd stumbled across a github package that addressed this properly, and after trawling through my search history I finally found it. Check out typescript-is - though it requires your code to be compiled using ttypescript (I am currently in the process of bullying it into working with create-react-app, will update on the success/failure later), you can do all sorts of crazy things with it. The package is also actively maintained, unlike ts-validate-type.

You can check if something is a string or number and use it as such, without the compiler complaining:

import { is } from 'typescript-is';

const wildString: any = 'a string, but nobody knows at compile time, because it is cast to `any`';

if (is<string>(wildString)) { // returns true
    // wildString can be used as string!
} else {
    // never gets to this branch
}

if (is<number>(wildString)) { // returns false
    // never gets to this branch
} else {
    // Now you know that wildString is not a number!
}

You can also check your own interfaces:

import { is } from 'typescript-is';

interface MyInterface {
    someObject: string;
    without: string;
}

const foreignObject: any = { someObject: 'obtained from the wild', without: 'type safety' };

if (is<MyInterface>(foreignObject)) { // returns true
    const someObject = foreignObject.someObject; // type: string
    const without = foreignObject.without; // type: string
}
Geoff Davids
  • 887
  • 12
  • 15
4

You can validate a TypeScript type at runtime using ts-validate-type, like so (does require a Babel plugin though):

const user = validateType<{ name: string }>(data);
edbentley
  • 191
  • 10
3

Type guards in Typescript using Reflect

Here is an example of a type guard from my Typescript game engine

 export interface Start {
    /**
     * Start is called on the frame when a script is enabled just before any of the Update methods are called the first time.
     */
     start(): void
 }


/**
  * User Defined Type Guard for Start
  */
 export const implementsStart = (arg: any): arg is Start => {
     return Reflect.has(arg, 'start')
 } 


 /**
  * Example usage of the type guard
  */

 start() {
    this.components.forEach(component => {
        if (implementsStart(component)) {
            component.start()
        }  

    })
}
Björn Hjorth
  • 2,459
  • 5
  • 25
  • 31
2
export interface ConfSteps {
    group: string;
    key: string;
    steps: string[];
}
private verify(): void {
    const obj = `{
      "group": "group",
      "key": "key",
      "steps": [],
      "stepsPlus": []
    } `;
    if (this.implementsObject<ConfSteps>(obj, ['group', 'key', 'steps'])) {
      console.log(`Implements ConfSteps: ${obj}`);
    }
  }
private objProperties: Array<string> = [];

private implementsObject<T>(obj: any, keys: (keyof T)[]): boolean {
    JSON.parse(JSON.stringify(obj), (key, value) => {
      this.objProperties.push(key);
    });
    for (const key of keys) {
      if (!this.objProperties.includes(key.toString())) {
        return false;
      }
    }
    this.objProperties = null;
    return true;
  }
Botond
  • 630
  • 6
  • 9
  • 4
    While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value. – xiawi Oct 18 '19 at 07:45
2

Another solution could be something similar what is used in case of HTMLIFrameElement interface. We can declare a variable with the same name by creating an object by the interface if we know that there is an implementation for it in another module.

declare var HTMLIFrameElement: {
    prototype: HTMLIFrameElement;
    new(): HTMLIFrameElement;
};

So in this situation

interface A {
    member:string;
}

declare var A : {
    prototype: A;
    new(): A;
};

if(a instanceof A) alert(a.member);

should work fine

Arnold Vakaria
  • 359
  • 2
  • 10
2

Not tested...

interface MySuperInterface {}

interface myInterface extends MySuperInterface {
    myObjectVariable: any
}

if ((myObject as MyInterface).myObjectVariable !== undefined)
Tristan
  • 21
  • 1
1

This answer is very simple. However, this solution is at least possible (though not always ideal) in maybe 3/4 of the cases. So, in other words, this is probably relevant to whomever is reading this.

Let's say I have a very simple function that needs to know a parameter's interface type:

const simpleFunction = (canBeTwoInterfaces: interfaceA | interface B) => { 
  // if interfaceA, then return canBeTwoInterfaces.A
  // if interfaceB, then return canBeTwoInterfaces.B
}

The answers that are getting the most upvotes tend to be using "function checking". i.e.,

const simpleFunction = (canBeTwoInterfaces: interfaceA | interface B) => { 
  if (canBeTwoInterfaces.onlyExistsOnInterfaceA) return canBeTwoInterfaces.A
  else return canBeTwoInterfaces.B
}

However, in the codebase I'm working with, the interfaces I'm needing to check mostly consist optional parameters. Plus, someone else on my team might suddently change the names names without me knowing. If this sounds like the codebase you're working in, then the function below is much safer.

Like I said earlier, this might strike many as being a very obvious thing to do. Nonetheless, it is not obvious to know when and where to apply a given solution, regardless of whether it happens to be a brutally simple one like below.

This is what I would do:

const simpleFunction = (
  canBeTwoInterfaces: interfaceA | interface B,
  whichInterfaceIsIt: 'interfaceA' | 'interfaceB'
) => { 
  if (whichInterfaceIsIt === 'interfaceA') return canBeTwoInterface.A
  else return canBeTwoInterfaces.B
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
John Miller
  • 388
  • 2
  • 8
  • 23
1

You can also send multiple inputs to child components, having one be a discriminator, and the other being the actual data, and checking the discriminator in the child component like this:

@Input() data?: any;
@Input() discriminator?: string;

ngOnInit(){
    if(this.discriminator = 'InterfaceAName'){
      //do stuff
    }
    else if(this.discriminator = 'InterfaceBName'){
      //do stuff
    }
}

Obviously you can move this into wherever it is applicable to use, like an ngOnChanges function or a setter function, but the idea still stands. I would also recommend trying to tie an ngModel to the input data if you want a reactive form. You can use these if statements to set the ngModel based on the data being passed in, and reflect that in the html with either:

<div [(ngModel)]={{dataModel}}>
    <div *ngFor="let attr of (data | keyvalue)">
        <!--You can use attr.key and attr.value in this situation to display the attributes of your interface, and their associated values from the data -->
    </div>
</div>

Or This Instead:

<div *ngIf = "model == 'InterfaceAName'">
    <div>Do This Stuff</div>
</div>
<div *ngIf= "model == 'IntefaceBName'">
    <div>Do this instead</div>
</div>

(You can use attr.key and attr.value in this situation to display the attributes of your interface, and their associated values from the data)

I know the question is already answered, but I thought this might be useful for people trying to build semi-ambiguous angular forms. You can also use this for angular material modules (dialog boxes for example), by sending in two variables through the data parameter--one being your actual data, and the other being a discriminator, and checking it through a similar process. Ultimately, this would allow you to create one form, and shape the form around the data being flowed into it.

  • note: in the scenario in the bottom, you would have a model variable that would tie to getters/setters or a variable in the typescript file. – Evan Crooks Jun 02 '22 at 14:24
0

Working with string literals is difficult because if you want to refactor you method or interface names then it could be possible that your IDE don't refactor these string literals. I provide you mine solution which works if there is at least one method in the interface

export class SomeObject implements interfaceA {
  public methodFromA() {}
}

export interface interfaceA {
  methodFromA();
}

Check if object is of type interface:

const obj = new SomeObject();
const objAsAny = obj as any;
const objAsInterfaceA = objAsAny as interfaceA;
const isObjOfTypeInterfaceA = objAsInterfaceA.methodFromA != null;
console.log(isObjOfTypeInterfaceA)

Note: We will get true even if we remove 'implements interfaceA' because the method still exists in the SomeObject class

troYman
  • 1,648
  • 16
  • 18
0

Simple workaround solution having the same drawbacks as the selected solution, but this variant catches JS errors, only accepts objects as parameter, and has a meaningful return value.

interface A{
    member:string;
}

const implementsA = (o: object): boolean => {
    try {
        return 'member' in o;
    } catch (error) {
        return false;
    }
}

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

implementsA(a) && console.log("a implements A");
// implementsA("str"); // causes TS transpiler error
Jack Miller
  • 6,843
  • 3
  • 48
  • 66
  • "and has a meaningful return value" in what way is a boolean return value better than a type guard like it is used in the selected solution? With your solution I would have to do a type assertion for no reason if I wanted to do anything specific with the object. – octagon_octopus Apr 09 '22 at 23:45
  • With "meaningful" I mean that you surely get a reliable return value without having to deal with errors. Depending on your use case this might be valuable or not. – Jack Miller Apr 19 '22 at 15:11
0

I know the question is a bit old, but just my 50 cents. This worked for me:

const container: Container = icc.controlComponent as unknown as Container;
if (container.getControlComponents) {
    this.allControlComponents.push(...container.getControlComponents());
}

Container is the interface, and icc.controlComponent is the object I wanted to check, and getControlComponents is a method from Container interface.

Faliorn
  • 1,351
  • 3
  • 12
  • 24
0

The premise of the question is that interface should provide runtime identification of what objects implement a given interface. But that's not how Interface has been designed in TypeScript because, as both the OP and others have said, Interfaces simply do not exist at runtime. The implications of that design choice is that at runtime, interfaces are no more than a collection of JavaScript object properties.

To do a runtime check, you can do the hacky thing of checking for the individual members in the interface:

interface A{
    member:string;
}

if(a.member) alert(a.member);

This is essentially what a lot of the proposed workarounds, including type guards, boil down to. This has obvious limitation when there are multiple members in the interface (should I check for them all? should I define an interface identifier/discriminator property?) and will in some cases require additional type checks on the members to pass the TS compiler's type checker. (E.g., another interface might implement member as number).

If the idea is to allow objects to exhibit behavior depending on what interfaces are present, then a better pattern is to use a base interface with a common method (or methods) to trigger behavior and then extend the base interface to add specialized properties and/or methods. Extending the OPs example:

interface A { //Base interface that all objects in the collection will implement
    talk():string
}

interface B extends A { //Specialized interface
    member: string
}

var a:A = {
    talk() {return 'got no member'}
}

var b:B = {
    member: 's',
    talk() {return 'my member is '+this.member}
}

for(let item of [a,b]) { //We can now loop over both object types and get the relevant response
    console.log(item, item.talk());
}

The point being that implementations of either interface are forced to implement a talk method with a common spec, which is enforced by the type checker. The compiler's type checking becomes increasingly valuable as the interfaces grow in complexity.

The biggest weakness of TypeScript's Interface is the lack of default implementations. You can fake it by defining a default object implementation of the interface and copying from it, like var defaultA = {talk() {'no member'}}; var a = {...defaultA}, but it would be much cleaner if it was possible to specify the defaults in the interface definition.

With many objects implementing the same interfaces, it is better to implement them as classes using the implements keyword in a class definition, which typically improves memory usage and performance. It also allows for multiple inheritance of interfaces and is another way to populate default behavior for objects.

dlm
  • 4,054
  • 2
  • 23
  • 19
-1

Here's the solution I came up with using classes and lodash: (it works!)

// TypeChecks.ts
import _ from 'lodash';

export class BakedChecker {
    private map: Map<string, string>;

    public constructor(keys: string[], types: string[]) {
        this.map = new Map<string, string>(keys.map((k, i) => {
            return [k, types[i]];
        }));
        if (this.map.has('__optional'))
            this.map.delete('__optional');
    }

    getBakedKeys() : string[] {
        return Array.from(this.map.keys());
    }

    getBakedType(key: string) : string {
        return this.map.has(key) ? this.map.get(key) : "notfound";
    }
}

export interface ICheckerTemplate {
    __optional?: any;
    [propName: string]: any;
}

export function bakeChecker(template : ICheckerTemplate) : BakedChecker {
    let keys = _.keysIn(template);
    if ('__optional' in template) {
        keys = keys.concat(_.keysIn(template.__optional).map(k => '?' + k));
    }
    return new BakedChecker(keys, keys.map(k => {
        const path = k.startsWith('?') ? '__optional.' + k.substr(1) : k;
        const val = _.get(template, path);
        if (typeof val === 'object') return val;
        return typeof val;
    }));
}

export default function checkType<T>(obj: any, template: BakedChecker) : obj is T {
    const o_keys = _.keysIn(obj);
    const t_keys = _.difference(template.getBakedKeys(), ['__optional']);
    return t_keys.every(tk => {
        if (tk.startsWith('?')) {
            const ak = tk.substr(1);
            if (o_keys.includes(ak)) {
                const tt = template.getBakedType(tk);
                if (typeof tt === 'string')
                    return typeof _.get(obj, ak) === tt;
                else {
                    return checkType<any>(_.get(obj, ak), tt);
                }
            }
            return true;
        }
        else {
            if (o_keys.includes(tk)) {
                const tt = template.getBakedType(tk);
                if (typeof tt === 'string')
                    return typeof _.get(obj, tk) === tt;
                else {
                    return checkType<any>(_.get(obj, tk), tt);
                }
            }
            return false;
        }
    });
}

custom classes:

// MyClasses.ts

import checkType, { bakeChecker } from './TypeChecks';

class Foo {
    a?: string;
    b: boolean;
    c: number;

    public static _checker = bakeChecker({
        __optional: {
            a: ""
        },
        b: false,
        c: 0
    });
}

class Bar {
    my_string?: string;
    another_string: string;
    foo?: Foo;

    public static _checker = bakeChecker({
        __optional: {
            my_string: "",
            foo: Foo._checker
        },
        another_string: ""
    });
}

to check the type at runtime:

if (checkType<Bar>(foreign_object, Bar._checker)) { ... }
Ledom
  • 1
  • 2
-2

Because the type is unknown at run-time, I wrote code as follows to compare the unknown object, not against a type, but against an object of known type:

  1. Create a sample object of the right type
  2. Specify which of its elements are optional
  3. Do a deep compare of your unknown object against this sample object

Here's the (interface-agnostic) code I use for the deep compare:

function assertTypeT<T>(loaded: any, wanted: T, optional?: Set<string>): T {
  // this is called recursively to compare each element
  function assertType(found: any, wanted: any, keyNames?: string): void {
    if (typeof wanted !== typeof found) {
      throw new Error(`assertType expected ${typeof wanted} but found ${typeof found}`);
    }
    switch (typeof wanted) {
      case "boolean":
      case "number":
      case "string":
        return; // primitive value type -- done checking
      case "object":
        break; // more to check
      case "undefined":
      case "symbol":
      case "function":
      default:
        throw new Error(`assertType does not support ${typeof wanted}`);
    }
    if (Array.isArray(wanted)) {
      if (!Array.isArray(found)) {
        throw new Error(`assertType expected an array but found ${found}`);
      }
      if (wanted.length === 1) {
        // assume we want a homogenous array with all elements the same type
        for (const element of found) {
          assertType(element, wanted[0]);
        }
      } else {
        // assume we want a tuple
        if (found.length !== wanted.length) {
          throw new Error(
            `assertType expected tuple length ${wanted.length} found ${found.length}`);
        }
        for (let i = 0; i < wanted.length; ++i) {
          assertType(found[i], wanted[i]);
        }
      }
      return;
    }
    for (const key in wanted) {
      const expectedKey = keyNames ? keyNames + "." + key : key;
      if (typeof found[key] === 'undefined') {
        if (!optional || !optional.has(expectedKey)) {
          throw new Error(`assertType expected key ${expectedKey}`);
        }
      } else {
        assertType(found[key], wanted[key], expectedKey);
      }
    }
  }

  assertType(loaded, wanted);
  return loaded as T;
}

Below is an example of how I use it.

In this example I expect the JSON contains an array of tuples, of which the second element is an instance of an interface called User (which has two optional elements).

TypeScript's type-checking will ensure that my sample object is correct, then the assertTypeT function checks that the unknown (loaded from JSON) object matches the sample object.

export function loadUsers(): Map<number, User> {
  const found = require("./users.json");
  const sample: [number, User] = [
    49942,
    {
      "name": "ChrisW",
      "email": "example@example.com",
      "gravatarHash": "75bfdecf63c3495489123fe9c0b833e1",
      "profile": {
        "location": "Normandy",
        "aboutMe": "I wrote this!\n\nFurther details are to be supplied ..."
      },
      "favourites": []
    }
  ];
  const optional: Set<string> = new Set<string>(["profile.aboutMe", "profile.location"]);
  const loaded: [number, User][] = assertTypeT(found, [sample], optional);
  return new Map<number, User>(loaded);
}

You could invoke a check like this in the implementation of a user-defined type guard.

ChrisW
  • 54,973
  • 13
  • 116
  • 224