Open tylim88 opened 2 years ago
This would seem to follow from the PR text
https://github.com/microsoft/TypeScript/pull/40336
Type inference supports inferring from a string literal type to a template literal type. For inference to succeed the starting and ending literal character spans (if any) of the target must exactly match the starting and ending spans of the source. Inference proceeds by matching each placeholder to a substring in the source from left to right: A placeholder followed by a literal character span is matched by inferring zero or more characters from the source until the first occurrence of that literal character span in the source. A placeholder immediately followed by another placeholder is matched by inferring a single character from the source.
I don't really see a defect here; zero-length strings are weird to reason about and you could make an argument for changing either of these behaviors. Without a motivating use case to drive which one, changing it for the sake of changing it is just risk without benefit.
What zero-length strings are we looking at here? Are you saying that we could interpret `${infer P}`
as having a zero-length string between `${infer P}
and `
?
Would it be fair to say that one should have no particular expectations about what will come out of a pathological case like never extends F<infer T> ? T : never
in general?
update: written some silly stuff, dont bother
it is simply counter intuitive, because with never, we always expecting negative case
What? never
is defined to be the subtype of all types.
type M = never extends string ? true : false; // true
@RyanCavanaugh lmao, sorry, had a brain fart
Thinking about it more, I think the correct behavior is actually fairly straightforward when comparing this to object types (demonstrated below). Probably what's going wrong here is that we have an assumption somewhere that for any T
legal to be there in the first place, ${T} === T
. That's true for string
subtypes, but isn't true for never
.
// A = true
type A = never extends { x: string } ? true : false;
// B = unknown
type B = never extends { x: infer T } ? T : "no";
// C = unknown
type C = never extends [infer T, unknown] ? T : "no";
// D = unknown
type D = never extends [unknown, infer T, unknown] ? T : "no";
// E = string
type E = never extends `${infer X}#` ? X : "no";
// F = never, ?. Should be 'string'
type F = never extends `${infer X}` ? X : "no";
@RyanCavanaugh
sorry for that silly post, it is morning and my brain still being dumb
ok long thing short
I think it is normal to expect the P from never extends ${infer P}/
? P : 1 and never extends ${infer P extends X}/
? P : 1 is never
update:
judging from the last post, seem like it is going to be P from never extends ${infer P}
? P : 1 is string and never extends ${infer P extends X}
? P : 1 is X instead
Bug Report
π Search Terms
never extends
${infer P}
yield different result than never extends${infer P}/
π Version & Regression Information
TS 4.7
type is not what expected
β― Playground Link
playground
π» Code
π Actual behavior
${infer P}/
yield the same result as never extends${infer P}
${infer P extends X}/
yield X but never extends${infer P extends X}
always yield neverπ Expected behavior
${infer P}/
should yield never like never extends${infer P}
${infer P extends X}/
yield never like never extends${infer P extends X}
are these intended behaviors? kind of unintuitive