Checking whether a parameter belongs to a type in Typescript - typescript

How can I check whether a certain parameter belongs to a type I've defined in TypeScript?
For example:
type myType = {n:number}
let par = {n:3}
I want to check whether x is of the type mtType. If I use typeof par the returned value of it is the string "object". Thanks.

Take a look at the type guards section here. It is possible with the following syntax:
function isMyType(arg: any): arg is myType {
return arg.n !== undefined && arg.n === parseInt(arg.n);
}
and later in the code
if (isMyType(objectToCheck)){
// do something with the object as myType
}

Related

introspection on custom typescript type

I define a custom type in typescript
type MyType = 'left' | 'right';
How can I check a variable match with this type?
How can I iterate on the possible values of this type? (to create a corresponding select element for example)
It's not possible.
You have to write and use something like this:
type MyType = 'left' | 'right';
const MyTypeMeta = ["left", "right"];
There is an old discussion here on this subject, with a lot of linked issues. Maybe a hope with this message but nothing complete for now.
Adding type information at runtime is a stated non-goal of TypeScript. That means they don't want to allow you to define a type and then examine it at runtime.
However, the reverse is just fine: create an object that exists at runtime, and use TypeScript to infer type information about it. Here's one way to do it in your case.
First, add the following helper function:
function stringLiteralArray<T extends string>(...args: T[]): T[] {
return args;
}
This helps TypeScript infer an array of string literals instead of just string[].
Now you can make a runtime object called myType, and derive MyType from it:
const myType = stringLiteralArray('left', 'right'); // ('left'|'right')[]
type MyType = (typeof myType)[number]; // 'left' | 'right'
Then you have both runtime and compile-time type info. You can check if a variable is of that type with the following user-defined type guard:
function isMyType(x: any): x is MyType {
return myType.includes(x); // needs es2016 at least, or implement yourself
}
You can iterate myType at runtime, and you can do exhaustiveness checking on MyType at compile-time:
function foo(x: MyType): string { // error, not exhaustive
switch (x) {
case 'left': return 'L';
case 'rihgt': return 'R'; // error, 'rihgt' isn't 'left'|'right'
}
}
Hope that helps.
You cannot do that with a "simple type", but since Typescript 2.4 you can use enums with string values:
enum MyType {
LEFT='left',
RIGHT='right'
}
for (let i in MyType) {
console.log(MyType[i]); //will print "left" and "right"
}
It works because during runtime an object named MyType exists and its value is {RIGHT:'right',LEFT:'left'}.

Alternative ways to use User-defined type guards?

I'm reading about User-Defined Type Guards in the Typescript handbook. Say you have a union type that you want to narrow down as follows:
interface Bird{
fly();
layEggs();
}
interface Fish{
swim();
layEggs();
}
class SmallPet implements Fish,Bird{
constructor(){
}
fly() { console.log("fly")};
swim() { console.log("swim")};
layEggs() {console.log("laying eggs") };
}
function getSmallPet(): Fish | Bird{
return new SmallPet();
}
function isFish(pet: Fish | Bird): pet is Fish{
return (<Fish>pet).swim !== undefined;
}
let pet = getSmallPet();
if (isFish(pet))
pet.swim(); //works
The function isFish is a User-Defined Type Guard as mentioned in the handbook. My question is how does this work? I tried to achieve the same result in a more sloppy way, which wasn't obviously going to work:
pet is Fish;
pet.swim(); //doesn't work
Does Typescript have to parse a function that looks like a type guard to achieve this feature and subsequently narrow down the type with the function call? Is there no other way to have type guards?
User defined type guards have two functions:
Check at runtime whether a value is of a certain type
Tell the compiler that a value is of a certain type
If you know that your instance is of type Fish then you can simply:
(pet as Fish).swim();
And in your case you can also use the instanceof type guard:
if (pet instanceof SmallPet) {
pet.swim();
}
The guide says
A type guard is some expression that performs a runtime check that guarantees the type in some scope.
So when you use a type guard, the type checker will narrow the type of the instance for the current scope: the if block in this case
The same operation could be done using pet instanceof Fish in the if statement. The type checker does the same kind of narrowing for the current scope.

Typescript pattern matching with subtype of string literal type

export interface Action{
type: string;
}
export interface LoadTodos {
type: "LOAD_TODOS_ACTION"
}
export interface AddTodo {
type: "ADD_TODO_ACTION",
todo: Todo
}
export type KnownAction = LoadTodos | LoadTodosSuccess | AddTodo;
function isSomeType<T extends KnownAction>(x: any): x is T {
return x && typeof (x.type) === "LOAD_TODOS_ACTION";
}
let knownAction: actions.KnownAction = { type: "LOAD_TODOS_ACTION" };
if (isSomeType(knownAction)) {
let loadTodosAction = knownAction; // load Todos type
}
I'm expecting the behaviour above. I want to do this in a generic way so I don't want to repeat if, else statement in isSomeType function.Basically I want to convert string literal type into appropriate type based on 'type' property. My attempt was to do this:
function isSomeType<T extends Action>(x: any): x is T {
type p1 = T['type'];
return x && typeof (x.type) === p1;
}
But the message says: 'p1' only refers to a type but is used as a variable here.
Is there a way to do this?
Surprisingly the answer is: do nothing.
function isSomeType<T extends KnownAction>(x: T):T {
return x;
}
Basically typescript will interfere type automatically whenever function with the above signature is called.
EDIT:
let knownAction: actions.KnownAction = { type: "LOAD_TODOS_ACTION" }; // KnownAction type
let knownAction2 = isSomeType(knownAction) // LoadTodosAction type
Not a definitive answer, but I don't believe you can.
FWIW the recommended approach would probably be a switch on the discriminating member.
As for your code, you may be losing track of where type information is lost. The typeof operator will not be meaningful here. typeof is a runtime operation and even if you write type: "LOAD_TODOS_ACTION" in your code at runtime typeof x.type will return string which I expect is not helpful to you. A string literal type means that the only acceptable assignable value is that string, not that a new type is introduced.
So in order to achieve what you're looking for we'd need to be able to get an interface member's compile time type information. As far as I know, there is no way to do this. When there is one, this is possible, but until then I don't believe it is.

Typescript Unions interface and primitive

Condidering this example
interface fooInterface {
bar: any;
}
function(value: fooInterface | string) {
value.bar
}
The error is: Property 'bar' does not exist on type '(fooInterface | string)'
I'm doing something wrong obviously. What I want to say basically is: value is EITHER an object implementing fooInterface or a string.
How can I do that?
Thank you
You can't use value.bar because it's not definitely safe. It might be safe (because value might be a string), but the compiler doesn't know that for sure, and it won't let you do .bar unless it's sure. What you probably want to do is use a type guard:
if (typeof value !== "string) {
value.bar
// This compiles happily, because inside this if, value has
// type 'fooInterface'. That's because TS now knows it isn't a string,
// so *must* be a fooInterface.
}
You can play around with this in the typescript playground: notice that only one of the value.bar's fails, because it knows that only that one is wrong.
If you can't/don't want to do this you can instead just tell the compiler you know what you're doing with a type assertion (e.g. var definitelyFoo = (fooInterface) value), but a guard is usually the better choice.
If, you are telling that value is either of type fooInterface or string, you have to check the type before you can work with the value. In your case you simply check whether value is string using typeof. If not, it is fooInterface.
interface fooInterface {
bar: any;
}
function(value: fooInterface | string) {
if (typeof value === "string") {
// The compiler now knows that value is string
}
else {
/* The compiler is smart and knows that the value
must be of type fooInterface. */
value.bar
}
}
In other cases you would have to use instanceof (for checking whether object is typeof specific class) or your own type checks (if there were multiple interfaces or custom types).

Return class type in TypeScript

If we write this:
class A {}
function foo(): A {
return A; // No error. Why?
}
function foo2(): A {
return new A(); // Ok.
}
function bar(): typeof A {
return A; // Ok.
}
function bar2(): typeof A {
return new A(); // Error. It´s ok.
}
Type of A is not A, instead it is typeof A. So I don´t understand why first example works.
Thanks.
Because of duck typing. A has no members, so typeof A is assignable to A.
Contary is not the same: typeof A has a constructor, so A cannot be assigned to typeof A.
When asking Typescript to verify a return type A, you actually telling Typescript to make sure that the return value should structure as an instance of A.
When you return A, you are actually returning the prototype of A (typeof A)
So, in your case A is just an empty object with no fields so A and new A() have the same structure, so no error.
When you define a return type typeof A TypeScript will compare the prototype of the function A (Class is actually a prototyped function after all) with A this will also result in successful compilation.
But, when you compare the typeof A (The prototype of A) with an instance of A it is not the same. your compilation will return an error.
To sum it up:
The prototype of A which is {}, has all the fields of A which is {} -> pass
An instance of A is {} and it also contains all the fields of A which is {} -> pass
The prototype of A which is a constructor function with no static fields, but fulfill the required {}, is the same as A which is {} -> pass
An instance of A which is {} is not the same as the prototype of A which has an extra constructor function -> fail

Resources