x9.is
generates runtime type-guards for any type so you don’t have to :)interface Person {name: string;}
x9.is<Person>({ name: 'Bob' }); // true
x9.is<Person>(7); // false
It works with generics too
interface Boxed<T> { value: T;}x9.is<Boxed<string>>({ value: 'lala' }); // true
It can also be used as a type guard:
if (x9.is<Person>(bob)) { console.log(bob.name);}
x.isLike
or x9.hasStructure
? My concern is that people will do this: x.is<Promise>
or x.is<Error>
(expecting it to perform an instanceof
check). In general, the distinction between structural compliance and the prototype chain is not well understood. So, instead of asking developers to learn about it, we can just stay far, far away from instanceof
and make it clear everywhere that this is all about structures. Even get the compiler to emit a warning if we find some ambiguity.At runtime, function values don’t carry any information. They are just function
s. This means that the best we can do is tell you if somethig is or isn’t a function.
// works as expected
x9.is<() => any>(() => {}); // true
// the following should be false,
// since the return types don't match
// but this information won't be available at runtime
x.is<() => string>(() => 5); // true
// the following should be false
// since the parameters don't match
// but it will still be true
x9.is<(x: string) => any>(() => {}); // true
The compiler will emit a warning if it determines you’re checking for functions.
Note: The number of arguments for a function is also available at runtime (via function.length
). However, this information is unreliable(ex: code could go through transformations that use rest parameters or rely on the arguments object, etc). For this reason, we prefer to discard it altogether.
Note: We need feedback here.
For example:
// when you declare a classclass Person { constructor(public readonly name: string) {}}// TypeScript automatically generates the following interfaceinterface Person { readonly name: string;}
So when you reference the Person
identifier, you can be referencing either the class “value” (the constructor function) or the class “type” (the interface)