interface Foo {
bar?: {
baz?: string;
}
}
declare let foo: Foo | undefined;
[|foo && foo.bar && foo.bar.baz|]
It should be possible to convert that chain into the following:
interface Foo {
bar?: {
baz?: string;
}
}
declare let foo: Foo | undefined;
foo?.bar?.baz;
You know, mostly like this
maybe a code-mode or babel transform that runs throughout a codebase?
@Urigo That could be done too, but I think having this granularity is good because it's not strictly the same semantics. ?.
always returns undefined
, &&
keeps the original nullish value.
Also keep in mind that optional chaining returns true
on 0
and ''
(empty string), normally falsy values in javascript. So running this as a code mod would almost certainly cause unintended bugs.
Also keep in mind that optional chaining returns
true
on0
and''
(empty string), normally falsy values in javascript. So running this as a code mod would almost certainly cause unintended bugs.
I'm not sure I really follow. Such code would be rather questionable in the first place, no? If you have an &&
chain that could be converted to an optional chain, and it returns ''
or false
as a short-circuit, then the same code would be throwing a TypeError if the value is a non-empty string or true
.
I could certainly envision a scenario where code was written that depends on short-circuiting on falsy values. We're eternally stuck with typeof null === 'object'
for backward compatibility reasons, after all.
Also there's no TypeError because boolean and string are object-coercible. The subsequent property access would just return undefined
and short-circuit.
[|foo && foo.bar && foo.bar.baz|]
What do the “|” mean?
@jineshshah36 [|code|]
is the syntax used typescript four-slash tests to mark a selection. Some diagnostic suggestions are not exposed unless they can be applied to the selected code.
All too eager to start using the ?. syntax I managed to play a trick on myself by converting
if (foo && foo.bar && foo.bar.indexOf(someValue) !== -1)
to
if (foo?.bar?.indexOf(someValue) !== -1)
which had quite the opposite behaviour of what was intended heh.
Just one of the (probably more obvious in hindsight) things a script would have to keep in mind :)
There's a question of whether or not nullish coalescing (??
) should be supported here as part of the code action.
Also, what the supported patterns are:
Category | Input | Output | Comments
-------|----------|-------|-------
&&
property chains: | a && a.b.c && a.b.c.d
| a?.b.c?.d
|
Ternary checks with property access | a.b ? a.b.c : "hello"
| a.b?.c ?? "hello"
| Is this one type-driven? What if c
is string \| null
?
&&
property/call chains: | a && a.b.c && a.b.c()
| a?.b.c?.()
|
Ahhhh, i have some existed work about this. And I'm happy to port here
I’m not sure of the viability of going after library refactorings (as opposed to just JS -> TS), but I think one huge win would be if TS could automatically refactor lodash/get usages and/or ramda/pathOr usages.
if TS could automatically refactor lodash/get usages and/or ramda/pathOr usages.
Good idea. IMO TypeScript cannot provide that but there's outside tools.
eg: https://github.com/HearTao/ts-upgrade
Are there any existed tools or algorithms to compare expression and judge they are equality?
I have some ugly work about it but they cannot work well.
Most helpful comment
You know, mostly like this