Inner inference doesn't inherit the contextual type from the outer one in argument position
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 42/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Đình trệ
- Công nghệ
- typescript
- Lĩnh vực
- compilers
Hướng nghiên cứu
Bắt đầu trong src/compiler/checker.ts tại inferTypeParameters và phần xử lý kiểu theo ngữ cảnh liên quan xung quanh getContextualTypeForObjectLiteralElement. Tái hiện vấn đề bằng mã TypeScript Playground được cung cấp, sau đó theo dõi lý do lời gọi lồng nhau nhận unknown thay vì Pattern<'a' | 'b'>; công việc hoàn tất khi cả dạng đối số nguyên thủy và dạng đối số đối tượng đều được suy luận nhất quán mà không cần userland workaround.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Bug Report
🔎 Search Terms
contextual type nested inference
🕗 Version & Regression Information
- This is the behavior in every version I tried
⏯ Playground Link
Playground link with relevant code
💻 Code
const matcher = Symbol("@ts-pattern/matcher");
type MatcherProtocol<input> = {
match: <I>(value: I | input) => void;
};
interface Matcher<input> {
[matcher](): MatcherProtocol<input>;
}
type Pattern<a> =
| Matcher<a>
| (a extends readonly [any, ...any]
? { readonly [index in keyof a]: Pattern<a[index]> }
: a extends object
? { readonly [k in keyof a]: Pattern<a[k]> }
: a);
type Match<i> = {
with<p extends Pattern<i>>(pattern: p): void;
};
declare function match<input>(value: input): Match<input>;
declare function union<input, ps extends [Pattern<input>, ...Pattern<input>[]]>(
...patterns: ps
): Matcher<input>;
declare function when<input, p extends (value: input) => unknown>(
predicate: p
): Matcher<input>;
// those have broken inferences
match<"a" | "b">("a").with(union("a"));
match<"a" | "b">("a")
// @ts-expect-error
.with(union("this is wrong"));
match<"a" | "b">("a").with(
// this should not be an error, since `x` should be `'a' | 'b'` and not `unknown`
when((x) => { let a: "a" | "b" = x; return x; })
);
// those have correct inferences
match<{ type: "a" | "b" }>({ type: "a" }).with({
type: union("a"),
});
match<{ type: "a" | "b" }>({ type: "a" }).with({
// @ts-expect-error
type: union("this is wrong"),
});
match<{ type: "a" | "b" }>({ type: "a" }).with({
type: when((x) => { let a: "a" | "b" = x; return x; }),
});
🙁 Actual behavior
In cases with match<"a" | "b">("a").with(...) the inference is broken whereas in cases with match<{ type: "a" | "b" }>({ type: "a" }).with(...) things work as expected.
🙂 Expected behavior
Both cases should work the same as the position in the with's argument should not matter.
This is a distilled case from ts-pattern by @gvergnaud . The real thing (equivalent of this repro case) can be tested out in this TS playground.
In the broken case, in inferTypeParameters (for the nested call):
- the
contextualTypeisp - the
inferenceTargetTypeisMatcher<input> - and the
instantiatedTypegets calculated asneversince it's using theouterMapperwithInferenceFlags.NoDefault. This in turn assignssilentNeverTypeto theinferredTypehere - all of this leads to inferring
unknownwhen a better inference could have been found (Pattern<'a' | 'b'>)
In the working case, within the same inferTypeParameters we get those:
inferenceTargetType->Matcher<input>contextualType->Pattern<"a" | "b">instantiatedType:Pattern<"a" | "b">
It's worth noting down that outerMapper is the same in both cases (p -> never) but in the working case it's simply not used because the contextualType has no type variables so instantiateTypeWithAlias returns early with the supplied argument here (Pattern<"a" | "b">).
Looking at the previous steps we can learn that the returned contextualType here is better in the working case because getContextualTypeForObjectLiteralElement checks getApparentTypeOfContextualType and there:
contextualType->pinstantiatedType->papparentType->Pattern<{ type: "a" | "b"; }>
Thanks to that the getTypeOfPropertyOfContextualType can return Pattern<"a" | "b"> here in the getContextualTypeForObjectLiteralElement.
It's also worth noting that the current version of ts-pattern works OK because we can "observe" this whole silentNeverType in the userland (which, I think, shouldn't be possible) here and we can return there what we originally expected there to be computed for us. The minimal repro case from this issue with this "hack" being applied can be found here
- Ngôn ngữ chính
- Go
- Star
- 111k
- Fork
- 14.4k
- Merge trung bình
- 1 ngày 19 giờ
- Pull request đã merge (30 ngày)
- 117
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của microsoft/TypeScript
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
microsoft/TypeScript#64322 · 2 bình luận · 1 reaction · 2 người được giao ·
-
Possible Improvement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
microsoft/TypeScript#64278 · 1 bình luận · 1 reaction ·
-
Docs
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
microsoft/TypeScript#64118 · 1 bình luận ·
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 88/100
microsoft/TypeScript#64094 ·
-
Docs
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
microsoft/TypeScript#63959 · 5 bình luận ·
Tất cả issue của microsoft/TypeScript
Issue tương tự
-
optimization optimization:agents-md-curator
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 86/100
githubnext/gh-aw-cao#13143 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
blinklabs-io/bursa#904 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
yanet-platform/ipfw-go#129 ·
-
bug confmap/provider/googlesecretmanagerprovider needs triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
open-telemetry/opentelemetry-collector-contrib#51273 · 2 bình luận ·
-
bug: AI Gateway client filter lists "Unknown" twice when NULL and literal Unknown clients coexist Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 90/100