Skip to content

Instantly share code, notes, and snippets.

@Insulince
Last active March 8, 2019 17:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Insulince/8f9626c3021260600e3151da947280c0 to your computer and use it in GitHub Desktop.
Save Insulince/8f9626c3021260600e3151da947280c0 to your computer and use it in GitHub Desktop.
Type narrowing an object based on the presence (or lack thereof) of the very type narrowing function itself on that object.

Meta Type Narrowing

class Model {
  static isModel(object: any): object is Model { // `object` is an instance of `Model` class, if...
    return !!object && // It is truthy AND...
      !!object.__proto__.constructor.isModel && // It contains a static property with the same name as this function AND...
      typeof object.__proto__.constructor.isModel === "function"; // That static property is a function.
  }
}

Explanation

This class contains a static type narrowing function which will check if the object passed to it is of the same type as this class by checking if the object passed to it contains the very static function by which this check is executed.

While this isn't completely fool-proof, it is sufficient to be highly confident that the type narrowing is correct.

The only way you could get a false positive is if the object you passed to the function ALSO happened to contain a static function with the same name. This suggests the more unique you can make your function name, the more likely your type narrowing is correct.

Example usages

Model.isModel(null); // false
Model.isModel(new Set()); //false
Model.isModel(); //false
Model.isModel({foo: "bar"}); // false
Model.isModel(new Model()); // true

Unverified assumptions

Some assumptions were made based on observation, but may be wrong in some edge cases.

  • Truthy values always contain a __proto__ property
  • The __proto__ property always contains a constructor property.
  • Static properties exist directly on the constructor property.
  • Non-static properties DO NOT exist on the constructor property, they exist either on the instance itself (for non-function properties) or on the __proto__ property of the instance (for function properties).
class Model {
static isModel(object: any): object is Model { // `object` is an instance of `Model` class, if...
return !!object && // It is truthy AND...
!!object.__proto__.constructor.isModel && // It contains a static property with the same name as this function AND...
typeof object.__proto__.constructor.isModel === "function"; // That static property is a function.
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment