-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Suggestion: short-circuit type inference for ternary operators when both branches have the same type #38399
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
Comments
So, the culprit here is the type generated by: type IntrinsicElements = JSX.IntrinsicElements[keyof JSX.IntrinsicElements] This creates a union of 108 object types each with over 300 properties. The types are all similar because they share a large number of data properties, but they are also subtly different in their event handler properties because of explicit target types. This union type is then further subjected to four layers of mapped and conditional types that add a bunch of new type identities. But then the really bad thing that happens is the subtype reduction kicked off by the ternary operator in Now, in reality the definition of type IntrinsicElements = JSX.HTMLAttributes<HTMLElement> | JSX.SVGAttributes<SVGElement>; Basically either I suppose I could be missing somthing, but otherwise that's the fix I'd suggest. |
Also, the type IntrinsicElements2 = IntrinsicElements |
{ [K in keyof IntrinsicElements]-?: K extends "accept" ? [string] : never };
type IntrinsicElements3 = IntrinsicElements2 |
{ [K in keyof IntrinsicElements]-?: K extends "class" ? [boolean] : never };
type IntrinsicElements4 = IntrinsicElements3 |
{ [K in keyof IntrinsicElements]-?: K extends "id" ? [number] : never }; This flattens the type into a union instead of stacking multiple mapped types on top of each other. Even more efficient is to have a single type do the augmentation: type IntrinsicElements4 = IntrinsicElements |
{ [K in keyof IntrinsicElements]-?:
K extends "accept" ? [string] :
K extends "class" ? [boolean] :
K extends "id" ? [number] :
never
}; |
@ahejlsberg thanks for the tips on improving the typings. Unfortunately, this does not produce the same result, as it doesn't allow me to assign the enhanced value: export type Property<
T = PropertyValue
> = {
[K in keyof T]: K extends "data"
? T[K] | [DefaultValue]
: T[K]
}
export type Property2 = PropertyValue | {
[K in keyof PropertyValue]-?: K extends "data"
? [DefaultValue]
: never
}
// works
const a: Property = {
type: ValueType.PROPERTY,
kind: "border",
data: [
{ type: ValueType.IDENT, data: "initial"}
]
}
// doesn't work, see error message below
const b: Property2 = {
type: ValueType.PROPERTY,
kind: "border",
data: [
{ type: ValueType.IDENT, data: "initial"}
]
} The latter results in:
Note that my intention was to enhance a specific member of each type of a union with a new type, in this case Also, note that this repository is only meant to reproduce the ternary performance bottleneck, so I'm quite aware that the typings are non-sensical. |
@squidfunk Is this comment a good example of the sort of thing you'd like the optimized types to be able to handle? What we need is a clear understanding of your goals so that we can identify/invent a more performant way to accomplish them (maybe). |
@amcasey Yes, that's one of the things that slow the compiler down when munching through my codebase. Also, as posted in this issue, enhancing of unions is something I use a lot. Maybe it's really worth trying to compile some popular projects which use generics with 3.9.1 and trace down performance bottlenecks, as I discovered in #38339 (comment). |
@squidfunk We've been building popular OSS projects looking for perf issues, but it's very valuable to have author input on intentions and expectations. Otherwise, it's hard to for us to tell whether the performance we're seeing is worse than it ought to be and whether the types can be changed without losing something important. |
That sounds like a good approach. It would be awesome if @ahejlsberg could comment on #38399 (comment) when he finds some time, as I'd really like to reduce the pressure put on the compiler without losing type safety 😊I haven't found a better approach, but if there is, it would be documented here. |
From https://github.com/squidfunk/typescript-issue-38339-repro (courtesy of @squidfunk)
TypeScript Version: 3.9.1-rc
Search Terms:
Subtype reduction, ternary
Code
Expected behavior:
return t
andreturn true ? t : t
check in a comparable amount of timeActual behavior: the ternary is much slower
Playground Link: https://www.typescriptlang.org/play/?ts=Nightly#code/JYWwDg9gTgLgBAbzgKQMoA04F84DMoQhwBEYUApgIYDGMxAUPTAJ5jlwCSAdjFMFwGdg1AKIAbciHI8BcALwoMAOm69+Q0RKkyA2gGtyzCLkXoVPPoOHjJ0mAIC6jcgA9IsOCzacL661rsBACYAHno4OAAVeR81K01bGXoAPhiEcLgdAGk4fjgDIxNIhwAuOBzXGGkAE1liGmpyMDoMiIB+KOyHOAAfTIE4gHMnCIiyyK76LGc3aHgvdlVLDRttewBmMIjohSW-BLXglLSM7NyufMNjKNLyuEqauuoxSgEBBlG4Doms7r6dABGEAgEkoXBGo3Gk2m9Fc7nmrEWvniq0CABYtlEYnsUQEZOtjgp0hEznkCtdimUKi4qlxaiRgNUPqNvl1epkuABXEAA8hQCFjTq-KYzeF4TlcWjACAXXDAgAUAEoyjiVnj7Gj2RLquRcPxyNVEBkJPMVci1YkNVq6br9dUMgB6B0UGCcqAXeBOuAAMVeMAyLrdHqgnPYHXgZU9DrgqDEEAA7iKgA
Related Issues: #38339
The text was updated successfully, but these errors were encountered: