-
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
Contextually type array literals as tuples when used in readonly contexts #38727
Comments
@ahejlsberg thoughts on doing this as part of your current tuple work? Seems compelling |
This may be a breaking change if somebody uses existing inferred array type in computation of other types, for example: const a = [1, 2, 3]
function b (param: typeof a) { ... }
// Works now, but will produce an error after this change
const c = b([1, 2, 3, 4]) So, the better way is to add a new compiler option that will make type checker infer types as narrow as possible: #38831 |
@awerlogus you seem to be misunderstanding this proposal- your example will continue to work exactly the same. This only affects tuples which are contextually typed in a readonly context. Since See the section on breaking changes for the places that are affected. Non-generic code will never show any difference in behavior. |
We already support inferring tuple types when the contextual type is a tuple type or a union that includes at least one tuple type. The latter means that you can generally just union with function call<TS extends readonly unknown[] | []>(
sources: TS,
func: (...args: TS) => number,
): number {
return func(...sources);
} So, I think we already have what you need. |
That's a bit "hacky" but it does solve this particular problem! |
Search Terms
Suggestion
The following example currently produces an error, since the type of
["abc", 100]
is inferred as(string | number)[]
, which means thatTS
is inferred asreadonly (string | number)[]
.Instead, we can type
["abc", 100]
as[string, number]
automatically by observing that it's being used in a readonly context (parametersources: TS
whereTS: readonly unknown[]
).Use Cases
Well-typed tuples in contexts like the
call
function above.Some workarounds already exist, but they aren't ideal.
Unsatisfying Workarounds
Add Typing Annotations
With an explicit type annotation,
call<[string, number]>(["abc", 100], func)
can be made to work, but this can be tedious or difficult if the values in the tuple have complex types.Add
as const
With an explicit
as const
call(["abc", 100] as const, func)
can be made to work, but this can sometimes do "too much" - it now causes"abc"
and100
to be literally-typed. If they were object values, their fields would becomereadonly
even if that wasn't desired. It also requires extra effort on the part of a library's users, which could cause libraries to shun this approach due to an apparent lack of ergonomics.Add lots of overloads
Manually adding overloads
This approach is repetitive, incomplete (always could need more tuple arguments), and deals poorly with highly-generic code (essentially, requiring the same piecemeal approach for all generic callers).
Examples
With this feature, all of the following can type-check, without needing any annotations at use-sites:
Breaking Change?
By restricting to
readonly
contexts (i.e. where the contextual type extendsreadonly unknown[]
), the number of breaking changes is minimal. In non-generic cases, the tuple type will immediately "decay" to its current array type, with no user-facing change.In generic contexts, tuples will generally only become more-precise. There are a few cases that may behave differently:
It's unclear whether this pattern appears in real-world code, or if the new typing is problematic (if the array is used mutably, it may behave incorrectly; if the array is used in a read-only manner, there is no change in behavior). My prototype in the TypeScript codebase didn't find any regressions in the compiler tests.
Requiring that the array constraint be
readonly
drastically limits the fallout of this change, since it's uncommon (even for generic functions) to use it.Checklist
My suggestion meets these guidelines:
I'm also interested in contributing this change. I have a working prototype implementation.
The text was updated successfully, but these errors were encountered: