Skip to content
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

Design Meeting Notes, 1/5/2018 #21037

Closed
DanielRosenwasser opened this issue Jan 5, 2018 · 0 comments
Closed

Design Meeting Notes, 1/5/2018 #21037

DanielRosenwasser opened this issue Jan 5, 2018 · 0 comments
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Jan 5, 2018

Conditional Types

#12424

[[Reiteration of points from #20724.]]

  • Lots of frameworks that do their own special cased values to make properties reactive/observable (MobX, Vue, Knockout).
    • Can specially handle these at the type system
  • This syntax can be broken down to two things:
    • C ? T : F
      • C = true or C = never implies T
      • C = false implies F
      • C = any or C = boolean implies T | F
    • X extends Y
  • The former seems reasonable.
  • The latter seems questionable outside of the first's context.
  • Originally, we just had one syntax: C extends D ? T : F
    • Why'd we break them out? Well, composability for type combinators.
      • But you can still build it all up!
        type Is<T, U> = 
        type If<C extends boolean, T, F> = C extends true ? T : F
        type Not<T extends boolean> = If<T, false, true>
        type And<C1 extends boolean, C2 extends boolean> = If<C1, C2, false>
        type Or<C1 extends boolean, C2 extends boolean> = If<C1, true, C2>
  • What if you have T extends Foo was its own type operator?
    declare function f<T>(x: T, y: T extends string);
    • That example basically says "take a T, and if T is a string, y must be true, or false otherwise"!
    • Weird! Is it useful? Probably not.
  • What about being able to narrow types?
    type DeepReadonly<T> = T extends any[] ? ReadonlyArray<T[number]> :
                           T extends object ? DeepReadonly<T> :
                           T;
    interface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {}
    • You really need T to be narrowed to something that looks like an array in the true branch of the first conditional so that you can index in with number in T[number].
      • We can't say it just becomes T & any[] because you'd get any from T[number].
      • Need to be able to add to the constraint of a type parameter.
    • But if you use those And, Or, etc. combinators, it's not clear how exactly to flow the information about how types have been narrowed.
  • What about making T extends Foo its own syntax that can only be used in the conditional expression?
    • [[Lost context]]
  • Also want to be able to introduce new type parameters that are inferred from the pattern of the constraint.
    type ResultOf<F extends (...args: any[]) => infer R> = R;
  • We want to be able to add constraints to an existing type parameter - do we want to provide users the ability to do that?
    • No, these should only appear from narrowed conditional type branches.

    • What about expression contexts?

      function foo<T>(x: T) {
          return typeof x === "string" ? { value: x} : {}
      }
      • Do we want the return type T extends string ? { value: T } : {}?

Regex Validated Types

#6579

  • Syntax: regular expressions in type positions.
  • Figuring out whether two regular expressions are subsets of others is hard; each regular expression type is only assignable to itself, not to any other.
  • Each method on a regular expression can now act as a type guard.
    • Means that string literal types can be narrowed!
  • But do people really write a lot of credit card string literals in their code?
    • Really comes up more with things like CSS, HTML attributes like data-.+
  • If you test with Regex1, Regex2, and Regex3, do you get Regex1 & Regex2 & Regex3`?
    • Yes.
  • We could use this in the compiler to get pseudo-nominal types.
    • And these regexes could actually verify the data as well.
    • Not that we use regular expressions to validate right now...
  • Could this make RegexMatchArray more accurate?
    • Potentially possible, kind of hard.
  • How do these work with mapped types like { [P in /some-regex/]: T }.
    • Would need regex index signatures.
      • Want that! But we have a lot of internal assumptions about number and string index signatures.
  • What about new features in regular expressions?
    • Should we only support a subset of regular expressions?
      • Either reimplement regexes, or rely on the runtime.
  • What about if these were more structural?
    • Would need some restrictions on the regex.
  • What does this add on top of nominality?
    • Really the type guards that you can get from string matching.
  • What about the exponential worst-case?
    • [[Out of time.]]

Stringly Typed

Guest: Mark Marron

Suppose (with pseudo-syntax...)

interface Formattable<T> {
    abstract static tryParse(str: string): T | undefined;
    abstract format(): string<T>;
}

Example:

class Email extends Formattable<Email> {
    // ...
}

class Gmail extends Email implements Formattable<Gmail> {
    // ...
}

Imagine if the following could generate the above?

// Just what appear to be one-off regexes:
type format UserName = /.../;
type format Domain = /.../;
type format Email = /^(UserName)@(Domain)/;
  • Problem is this affects emit, not part of TypeScript's design goals.
  • Could probably accomplish this by passing regexes to class factories.
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Jan 5, 2018
@microsoft microsoft locked and limited conversation to collaborators Jul 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Design Notes Notes from our design meetings
Projects
None yet
Development

No branches or pull requests

1 participant