-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Show both narrowed type and declared type #45870
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
I think this Workbench Repro shows the oddness being discussed pretty well: declare function getItem(): Promise<description: string}>
async function main(): Promise<undefined | string> {
let _;
_= await getItem()
//^?
_= _.description
// ^?
_= parseInt(_)
//^?
_= isNaN(_) ? undefined : _
// ^?
_= _?.toPrecision(2)
return _
} |
Oh, I see, I misunderstood. It's about the tooltip on the assignment side. |
Since accessors can now diverge in their types and have the same issue, I could imagine a notation like
|
One technical problem (I believe) is that in let x;
x = new Date()
// ^? by the point of assignment, control flow analysis hasn't changed the type of |
Really nice improvement! Would solving this issue also fix the narrowed-by-assignment code below? (playground) function toString(a: unknown) {
a = String(a);
return a;
// expected return type: String
// actual return type: unknown
}
toString(42).includes('4')
// ^^ Object is of type 'unknown'.(2571)
// explicitly declaring a return type doesn't work either
function toString2(a: unknown): string {
a = String(a);
return a;
// ^^ Type 'unknown' is not assignable to type 'string'.(2322)
} Or is this a different problem? If "different problem" then is there a better solution than declaring new variables (which has a runtime footprint that we'd prefer to avoid) or liberally using type assertions downstream from a type-narrowing mutation (which is verbose and bug-prone)? I'm asking because we're midway through porting the Temporal polyfill from JS to TS. We're just now getting to the part where we add type annotations to function return types and function parameters. But a lot of the old JS polyfill code mutates |
@justingrant I don't see how a local variable has any relevant runtime footprint, but you can use a Type Assertion here:
That an |
My naive expectation would be that because Is there a good issue or PR to read about the rationale for why one pattern narrows but the other doesn't? TS usually has good reasons for things that seem counter-intuitive, and I assume the same is true here too.
Probably no significant perf footprint (and avoiding reassignment might even be better perf depending on how engines optimize), but:
Yep, adding hundreds of type assertions is the runtime-invisible way to work around this problem and avoids the problems in the bullet points above. But it's not cost-free either:
dateAdd(date, duration, options = undefined) {
if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver');
date = ES.ToTemporalDate(date);
duration = ES.ToTemporalDuration(duration);
options = ES.GetOptionsObject(options);
const overflow = ES.ToTemporalOverflow(options);
const { days } = ES.BalanceDuration(
GetSlot(duration, DAYS),
GetSlot(duration, HOURS),
GetSlot(duration, MINUTES),
GetSlot(duration, SECONDS),
GetSlot(duration, MILLISECONDS),
GetSlot(duration, MICROSECONDS),
GetSlot(duration, NANOSECONDS),
'day'
);
return impl[GetSlot(this, CALENDAR_ID)].dateAdd(
date,
GetSlot(duration, YEARS),
GetSlot(duration, MONTHS),
GetSlot(duration, WEEKS),
days,
overflow,
this
);
} |
@DanielRosenwasser is there any specific reason why CFA doesn't change the type of I have a hacky fix for this locally that creates a fake |
Suggestion
π Search Terms
List of keywords you searched for before creating this issue. Write them down here so that others can find this suggestion more easily and help provide feedback.
β Viability Checklist
My suggestion meets these guidelines:
β Suggestion
π Motivating Example
https://twitter.com/Rich_Harris/status/1437490023763415043
is roughly a confusion on narrowed vs storage type of a given field/binding
π» Use Cases
Current UI / typing only shows what can be assigned to a value storage location given a source text location.
Need UI to show what can be used from a value storage location given a source text location.
Much of the time these should be the same but showing something about the narrowing would apparently remove some confusions, for example (bikeshed):
The text was updated successfully, but these errors were encountered: