Home > database >  Typescript Typeof not working as expected
Typescript Typeof not working as expected

Time:04-20

let y: Policyholder = this.person as Policyholder;
let x = typeof(y);

Policyholder is a class which implements the Person interface. At first this.person is of type Person but is then casted to a Policyholder.

Still, the value of x is not 'Policyholder' but object.

I thought that typeof only does not work with interfaces but should work with classes. If not even classes work, when and why would one even use typeof

CodePudding user response:

typeof works in runtime, therefore it have no relation to TypeScript in this scenario. You can use typeof to provide TS with additional information, as in let x: typeof y = some_value, but this will be stripped during build time and will not add anything in runtime.

If you want to be sure that you have specific instance, you can check with instanceof is indeed instance of some class or prototype object.

CodePudding user response:

Typescript only exists at compile time, so calling the typeof function will have the same effect in typescript code as it does in plain javascript code. typeof returns one of a few predefined strings, such as "number", "object", or "string". This can be used to distinguish between those broad categories, but won't help with figuring out the details of the object you're working with.

If your objects were created from a class, then you can use the instanceof operator to see if the object is an instance of that class. As with typeof, this behaves the same in typescript as in plain javascript. Typescript lets you describe your javascript code, so that issues can be identified at compile time and thus caught early; it doesn't give you new capabilities at runtime.

P.S.: There is a typescript-specific typeof operator that works at compile time, but you're not using it here and it's purpose is different than what you're trying to do

At first this.person is of type Person but is then casted to a Policyholder.

It's possible you have some misconceptions about what as Policyholder does in typescript, since it's different from some other languages. It doesn't change anything about the data. Whatever values were in memory for this.person before hand, they're still the same values afterwards.

It's better to think of this as a "type assertion", not a "type cast". It means "hey typescript, i know this object looks like [type x], but trust me, it's actually [type y]". This is sometimes necessary if you know something that typescript doesn't know, but if you assert the type and you were wrong, then typescript won't be able to tell you about the problem.

CodePudding user response:

This really doesn't have anything to do with classes or types vs. interfaces.

When you write code in a *compiled statically-typed language there are (at least) two different contexts you have to be aware of: a type context that only exists at compile time and a value context that only exists at runtime.

Typescript unfortunately has some shared syntax between them that makes this extra confusing, like typeof. For example:

const Foo = {}; // Value {}
type Bar = {};  // Type {}, could also use interface Bar {}
Foo === Bar; // Error! Foo is a *value*, Bar is a *type*, we can't use types in a value context
const Baz: Foo = {}; // Error! We can't use *values* in a *type* context!
const a: typeof Foo = {}; // works
const b: Bar = {}; // also works

N.B. this (compile-time) use is different than the use of typeof operator in a value (i.e. runtime) context:

console.log(typeof 'hello'); // logs the string 'string' at runtime

The compile-time use of typeof works more like you think it should: it will work with classes and when used with classes it will be the type of the class itself (not an instance of the class). It doesn't work on interfaces because it doesn't need to: interfaces are already a type.

In other words, the purpose of typeof in a type context is to take a compile-time known value like a constant primitive or object literal and make it into a type that we can use in a type context.

Also note that there are literals that can be used in both a type and value context, although like typeof the meaning changes depending on the context:

type A = 'a';  // literal type a
type Five = 5; // literal type 5
5 === Five; // Error! Five is a *type*

* We will for this answer ignore the existence of compiled dynamic languages like Clojure and statically-typed languages that let you run arbitrary code at compile-time like Zig.

  • Related