How to properly handle TypeScript values with multiple types

typescript dictionary type
typescript define type
typescript object key type
typescript function type
typescript is
typescript nullable type
typescript map
typescript mapped object type

I have following TS interface

export interface Item {
  product: string | Product;
}

When I want to literate through array of items I have to eliminate the type. In other words

items = Items[];
items.forEach(item => {
  item.product._id
})

is not going to work because property is is not appliable to strings. Hence I have to pre-check the type, i.e.:

items = Items[];
items.forEach(item => {
  if (typeof item.product === 'object') item.product._id
})

I don't really like how it looks. How do you handle this situation?

There should be type guards in order to narrow down the type:

if (item.product && typeof item.product === 'object') item.product._id

Or:

if (item.product && typeof item.product !== 'string') item.product._id

If there's a possibility that item.product is a string as the interface suggests, this check is needed.

Otherwise the type should be asserted:

items.forEach(item => {
  (item.product as Product)._id
})

Advanced Types · TypeScript, An intersection type combines multiple types into one. This allows A union type describes a value that can be one of several types. We use the PI * s.radius ** 2; } // should error here - we didn't handle case "triangle" }. There are Note: The Exclude type is a proper implementation of the Diff type suggested here. We've  TypeScript has two special types, null and undefined, that have the values null and undefined respectively. We mentioned these briefly in the Basic Types section. By default, the type checker considers null and undefined assignable to anything. Effectively, null and undefined are valid values of every type.

Javascript doesn't type variables, so I imagine your issue is only about your IDE.

The first and most obvious solution is to declare your variable as any. No further issue, but you won't have autocomplete.

Second solution, not practical, is to create a typed variable :

if (item instanceof Product) {
  _item: Product = item;
  // Now you have autocomplete on _item
} else if (typeof item === 'string') {
  _item: string = item;
  // Same here. 
}

This isn't practical because you will have to write 2 times your logic : once for the product, once for the string. But ! it may be not practical, but it is exhaustive, since you have to implement both logic (and they surely differ because you don't treat a string like an object, and vice versa).

Handbook - Unions and Intersection Types, How to use unions and intersection types in TypeScript. function padLeft ( value : string, padding : any) { if (typeof padding === "number") An intersection type combines multiple types into one. separate out the error handling into it's own type which is merged with types which correspond to a single response type. ts. How should i handle async calls that return multiple values? Both values have different types. Typescript seems to have issues with the types when a promise is

This may sound weird but the first/best approach should be "don't have a class variable with mixed type string | product".

What is your specific use case? Why are there some products as strings and some as classes? Is it possible to create an instance for the string classes as well?

If this is somehow not possible for some reasons, you can check with instanceof for the proper type (do not check with typeof === 'object', as it is not really safe)

if (item instanceof Product) { // do logic }}

Do's and Don'ts · TypeScript, Don't ever use the types Number , String , Boolean , Symbol , or Object These types Do use the return type void for callbacks whose value will be ignored: This code, for example, exposes a bug only when the signature is correctly written  Description If a schema is defined with the allOf operator with multiple values, the generated model is an interface that extends only the first value. openapi-generator version 3.2.2 OpenAPI declaration file content or url openapi: 3.0.

Conditional types in TypeScript, Overloading involves providing multiple type signatures for a single function, and letting A extends B means precisely that any value of type A can safely be assigned to a variable of type B It handles ambiguity gracefully:  TypeScript, like JavaScript, allows you to work with arrays of values. Array types can be written in one of two ways. In the first, you use the type of the elements followed by [] to denote an array of that element type: let list: number[] = [1, 2, 3]; The second way uses a generic array type, Array<elemType>: let list: Array<number> = [1, 2, 3];

typescript-cheatsheet, We may need to describe the type of variables that we do not know when we Next we'll see how to properly write Generics in TypeScript and different types of Generics. Webpack webpack.config.js file configuration to handle TypeScript:. The TypeScript compiler will generate errors, if we attempt to assign a value to a variable that is not of the same type. Hence, TypeScript follows Strong Typing. The Strong typing syntax ensures that the types specified on either side of the assignment operator (=) are the same.

A quick yet in-depth tour of TypeScript and its types, Types can be attached to variables with a colon (:) in their definition, like so: TypeScript has the ability to understand variables that can have multiple types. If you actually want to create a set that can hold both strings and  Given that we don't want to attempt to evaluate RHS expressions to resolve the same value functions, we're pretty much stuck using type information to infer the same thing. Or we could just forbid the re-declaration of exports, given that since you're forced the reexport the exact same value or error, there's no real value in doing so.

Comments
  • It depends; it's not really clear what you're trying to achieve, because the example you show doesn't do anything. But you could use type guards, see e.g. typescriptlang.org/docs/handbook/advanced-types.html
  • @jonrsharpe ectus already answered my question. Going to use type asserting (as you mentioned). Thats the clearest solution in my case.
  • Note that will only work in the case when all of the Items' product properties are Products, not strings, in which case allowing it in the original type seems pointless.
  • Its obvious. Initial reason to have multiple types was to check types and through error. Would radically simplify debugging in the future. Yet thank you for pointing it out
  • casting a type - I like it... Thank you
  • @Timothy asserting, not casting. If one of those is products is actually a string at runtime, the code will break (which is what the compiler's telling you to start with).
  • The reason I use it - is because this value literally might be either a string or an object. Depending whether MongoDB ObjectID has been populated with referenced object or not. In some callbacks it is is some not..
  • then again the question is why can't you represent your string value as product instance? If the fields of Product is are only name & id, I think the better approach is setting the type of id to number | null and always create product instances
  • No its not.. I am very much simplified the situation. The Product object is huge. Yet thank you for your answer.
  • K but then again, maybe your specific use case is to complex to describe here, I don't see how your product is either 1 String or an entire object with dozens of properties. I mean typesafety does not help you at all since you have to treat them completely different. And if you have to treat them differently it often does not make sense to have it in the same variable