Skip to content

Design Meeting Notes, 1/31/2020 #36623

@DanielRosenwasser

Description

@DanielRosenwasser

Should an Optional Chain Always Add undefined to the Type?

#36163 (comment)

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 get undefined.

    • 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
  • 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

#12754

  • 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.
  • 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design NotesNotes from our design meetings

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions