| ▲ | mdtrooper 5 hours ago | |||||||||||||||||||||||||||||||||||||||||||||||||
What has always bothered me about TypeScript are union types. If you have a function that receives a parameter such as ‘Dog | Cat’, you cannot separate it. For example: type Dog = { bark: () => void } type Cat = { meow: () => void } function speak(animal: Dog | Cat) {
}Okay, okay, I know you can filter using ‘in’ to see if it has methods, but in real life, in a company where you have a colleague (who is a golden boy) who writes over-engineered code with hundreds of interfaces of interfaces, you don’t want to spend time searching through the files to find every element that is in the union type. Whereas in Rust it does: struct Dog { name: String, } struct Cat { name: String, } enum Animal {
}fn process_animal(animal: Animal) {
}I think TypeScript should add a couple of lines of code to the generated JavaScript to do something like: type Dog = { bark: () => void } type Cat = { meow: () => void } function speak(animal: Dog | Cat) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | tshaddox 5 hours ago | parent | next [-] | |||||||||||||||||||||||||||||||||||||||||||||||||
The idiomatic way to do this in TypeScript is with discriminated unions. You’re basically just giving the type system an extra property that makes it trivial to infer a type guard (while also making the runtime check in the compiled JavaScript foolproof). | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | culi 4 hours ago | parent | prev | next [-] | |||||||||||||||||||||||||||||||||||||||||||||||||
Your first code block works exactly as you would expect and has been working like that for many years https://www.typescriptlang.org/play/?#code/C4TwDgpgBAIg9gcyg... | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | littlecranky67 5 hours ago | parent | prev | next [-] | |||||||||||||||||||||||||||||||||||||||||||||||||
Typeguard is what you are looking for: function isDog(animal: Dog | Cat): animal is Dog { return "bark" in Dog } Then: isDog(animal) ? animal.bark() : animal.meow() You get full type narrowing inside conditionals using typeguards. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | spankalee 5 hours ago | parent | prev | next [-] | |||||||||||||||||||||||||||||||||||||||||||||||||
You're talking about adding a runtime feature. TypeScript doesn't do that anymore. It can't control what properties are on objects or add new ones - you do that yourself in the standard JavaScript portion of the language. TypeScript only lets you describe what's there. As a sibling said, discriminated unions are they way to go here. You can also add custom type guard functions if you can't control the objects but you want to centralize the detection of the types, but it's better to let TypeScript do it itself so that you don't mess something up with a cast. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | castral 4 hours ago | parent | prev | next [-] | |||||||||||||||||||||||||||||||||||||||||||||||||
You can literally do what your generated example does using a type guard. You can also use method overloaded signatures if you dont want to expose your API consumers to union types. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | epolanski 5 hours ago | parent | prev | next [-] | |||||||||||||||||||||||||||||||||||||||||||||||||
You need a tagged union for this in typescript. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | paulddraper 4 hours ago | parent | prev | next [-] | |||||||||||||||||||||||||||||||||||||||||||||||||
You're looking for a discriminated union [1], which idiomatically:
Generally speaking, TypeScript does not add runtime features.TypeScript checks your use of JavaScript runtime features. [1] https://www.convex.dev/typescript/advanced/type-operators-ma... | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | zem 5 hours ago | parent | prev [-] | |||||||||||||||||||||||||||||||||||||||||||||||||
this post on union types versus sum types is worth a read (the tl;dr is that they both have their uses and one is not strictly better) https://viralinstruction.com/posts/uniontypes/ | ||||||||||||||||||||||||||||||||||||||||||||||||||