-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Typescript: Realistic type definition errors #35247
Comments
Kind of a difficult one. It's not always true that the fully expanded type is more readable than the type alias. I personally manually control the emit of my types (via type hackery) to try and get the best error message I can. (Rather than relying on TS' default emit algorithm) Maybe something like this?
Maybe also do a Levenshtein distance on valid strings and suggest the closest match? |
How do I get started on that? And I'm sure this is one of those threads that once you start pulling it never stops... but, never-the-less, it couldn't be any worse than it is for some of these errors. |
To force TS to expand types, To force TS to not expand types (situational, doesn't work for all cases), If you go down this rabbit hole, you may be cursed! The There are other tricks to force a type to be expanded if you can't rewrite a type to use the Try looking at One such trick is, type Identity<T> = T;
type Merge<T> = Identity<{ [k in keyof T] : T[k] }>; However, if Hence, my feature request here, #32909 A workaround is, type DistributeMerge<T> = T extends any ? Merge<T> : never; This merge trick can force the expansion of the top level object |
This is the most helpful response I think I've ever gotten to a GH issue. Thank you very much.... I'm going down the rabbit hole. |
A way to reproduce the error you saw would be very useful. We can sometimes improve error messages based on the use case. Anyway it's not at all clear what the right rule is here; if one way were just always better than the other, that's the one we'd be doing by now (one would hope). Let's say you had something like interface Options {
height: number;
length: number;
depth: number;
width: number;
color: string;
name: string;
orientation: string;
location: string;
age: number;
// 30 other properties
} and you use Somewhere, a function says function fn(opts: Partial<Omit<Options, "orientation">>) {
} and you call it incorrectly. What would you want to see?
where you will have to manually diff the property list to figure out which one got removed? That would be clearly worse in a lot of cases. You can't just rely on "Well if the alias appears in the code, then use that" rule either because these types can appear in higher-order forms, e.g. function fn<T, U extends keyof T>(obj: T, key: U, others: Partial<Omit<T, U>>) { where you'd still want the unexpanded alias form. |
I suppose the ideal would be some form of switching between the two. I don't expect that to have any easy way, but (if it was possible) it might be like:
Perhaps there is a way to pass this logic off to user land? There are some things I'd like to try. Speculatively, I think it might be effective to show flat versions of anything with a symbolic tree of over 3-4 nodes. Other times, it could perhaps fit both the symbolic and flat version one after another. I've been getting really into advanced, conditional, and utility types for my projects. |
A feature for this, mayhaps? |
@weswigham That would definitely be a good way to go about it. Really, anything works for me, as long as I can see what the final list of properties and types for them is. |
Your last two examples just look like type emit problems. The thing is, I feel like most people don't know how to get the current type system/emitter to produce "good" type emit. Especially for complex generic types. There are tricks for these things. But sometimes, the types are just too large and some amount of difficult-to-read output is unavoidable. So, errors can become unreadable, despite the team's best efforts, if users create types with unreadable emit in the first place. |
I've found a solution for my scenario, and it is to create facade types that are simple and assert their equivalency to my more complex (and realistic) types elsewhere. I'm not sure what the limitation of facade types is, but so far it's doing the trick. |
Type checking, and type definitions errors could me made significantly easier to debug by boiling down the type definitions to something realistic.
For this second example, it would be a lot more useful if instead it just showed what the type realistically is, and what it was missing. Ie:
This could be a configuration thing, but I can't imagine any reason why a person would want cryptic error messages by default.
The text was updated successfully, but these errors were encountered: