Design Meeting Notes, 1/31/2020
DanielRosenwasser opened this issue ยท 6 comments
Should an Optional Chain Always Add undefined
to the Type?
const arr = [1, 2, 3, 4, 5]
const j = Math.random() * 1000 % 1;
const k = arr[j]?.toFixed();
-
If index signatures included
undefined
, you'd getundefined
.- But this can go beyond that case.
-
Defensive code in general.
-
But we have plenty of places where we don't make
||
conservative.// Inferred to `number[]` because we // don't assume it *could* be null/undefined function foo(x: number[]) { return x || "hello" }
-
Okay, but are you going to trust that the user wrote
?.
for a reason, or assume we have a perfect type system? -
Seems like the indexing case is hard to explain to users
- Okay, but maybe we could fix the indexing case?
- Really a separate issue
- Okay, but maybe we could fix the indexing case?
-
Are people encountering this?
- It's a new feature, and the longer we wait, the more we may hear about this.
-
Why would you write
?.
on a defined type unless you planned to immediately handle them?- The indexing case?
- Then let's solve the indexing case.
-
Should we also change
||
and&&
?- Maybe!
- What!? This behavior is so old, who exactly are you helping by changing that?
- Pretty sure we need code like this to work because of how narrowing within arrays works today.
-
Discussion inconclusive
Augmenting Keys
-
Some demand to do two things:
- Slicing/dicing strings to convert from/to camelCase, kebab-case, etc.
- Filtering out types
- And maybe just concatenating literals
-
Would be nice to write
type Foo<T> = { [K in keyof T as StringConcat<"get-", K>]: T[K] };
-
Could you do something like the following?
type Foo<T> = { [K in StringConcat<"get-", keyof T>]: T[K] };
-
-
Created a prototype that wires up a bunch of type aliases that have special behavior:
type StringToUpper<K> = ...; // StringToUpper<"Foo"> -> "FOO" type StringToLower<K> = ...; // StringToLower<"Foo"> -> "foo" // StringSlice<"hello", 1> -> "ello" type StringSlice<K, Start extends number, End extends number> = ...; // StringConcat<"foo", "bar"> -> "foobar" type StringConcat<K1, K2> = ...; // StringMatch<"foo" | "bar" | "baz", "a"> -> "bar" | "baz" type StringMatch<K, Pattern extends string> = ...;
-
Won't these cause a lot of exponential explosions in the type system?
- Sure, but we already have those.
- Yes, But we're already trying to grapple with them.
- Sure, but we already have those.
-
Can we not use type aliases for everything here?
- Not clear that it's better.
- Strange that there's a magical name that has behavior instead of something core to the language.
- But creating more operators/keywords would be a lot of new work in the parser.
-
Many of these aren't useful on generics - what if we just let people write actual code to do this?
- Now you have to have a API on our type system.
-
Do we think this is something we want to solve?
- Need to see the use-cases - what are people doing today?
- Code generators? Index signatures?
- Can't necessarily say "yes", but probably not near-term. We should be focusing on speed.
- Need to see the use-cases - what are people doing today?
Why would you write ?. on a defined type unless you planned to immediately handle them?
People new to TS often carry the need to write defensive code everywhere even if it's unnecessary. If TS implicitly added | undefined
here, it would suddenly make these legitimate and make it necessary to add even more defensive code to handle the new undefined
values that aren't really there at runtime.
This also seems like it would break the no-unnecessary-condition lint rule, which is really useful for changing this behavior over time.
Misc. thoughts from a random user:
- For the string concatenation case, is there a reason we couldn't just use the
+
operator?- This would mean we'd have syntactic parity between value-level concatenation and type-level concatenation
- There's already precedent in Flow for built-in "type aliases" (e.g.
$Call
,$Exact
, etc), so it wouldn't be too crazy IMO if TypeScript were to introduce a few- In fact, for better or worse, doing so would allow you guys to special-case more complex typing solutions without adding new syntax (e.g.
$Awaited
,$Coroutine
, etc)
- In fact, for better or worse, doing so would allow you guys to special-case more complex typing solutions without adding new syntax (e.g.
We don't like the type aliases (especially the leading $
), but yeah, it's the easiest way to make this "scale".
Hey @DanielRosenwasser ,
are there plans to implement the string utility types? Are you seeking contributors for those? I'd like to help, as I'm very much interested in this feature. Although I have no experience working with the TS code base at all, I'd like to invest my time. Maybe it could help me fix one bug or another in the future ๐
No plans right now - we had a mock-up demonstrated at the design meeting, but the concern was more about complexity and speed.