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, 9/23/2016 #11104

Closed
mhegazy opened this issue Sep 23, 2016 · 6 comments
Closed

Design Meeting Notes, 9/23/2016 #11104

mhegazy opened this issue Sep 23, 2016 · 6 comments
Labels
Design Notes Notes from our design meetings

Comments

@mhegazy
Copy link
Contributor

mhegazy commented Sep 23, 2016

Literal types -- cont'd

Some setup:

  • every literal has a "domain", for instance true and false have a domain, which is boolean

  • declaring let x = true intends to make x go to the domain of hte literal type, which is boolean

  • same goes for enums

  • the problem with string and numeric literal types, the domain is all strings or numbers, and there is no way to declare a subset of this domain

  • type Direction = "up" | "down" | "left" | "right" declares a subdomain, yet when we widen we loose this information, and in a sense we do not distinguish values of this type from any other string

    function getEvent(): Event;
    const e = getEvent();  // e is Event
    let v = e;  // now v is string!!!
    `  ``
    
    ## Proposal:
    
    - intuition is that named type aliases is a declaration of intent by the user to cleave a sub-domain of all literal types..
    ```ts
    const c1 = "foo";
    const c2 = "bar";

const c3 = cond ? c1 : c2;
const c4: FooOrBar = cond c1 : c2;

let x = c3;
let y = c4;


there is some distinction about `c3` and `c4`. arguably `c4` has clearer intent. widening it would not be 

- track "freshness" of a literal type. a literal type with a type annotation is considered to not be "fresh", where as one that is inferred is considered as "fresh".
- freshness is tracked on the type throughout the system
- a fresh literal is assignable and sub-type of its "unfresh" version
- the only difference is that fresh widens to to string/number, where as the other doe not.

- so:
```ts
// A type annotation does not cause widening
type Result<T> = T | "FAILURE";
function doWork<T>():Result<T>;
let x = doWork<number>(); // number | "FAILURE";

// otherwise widening happen
function doWork2<T>() {
    return cond ? T : "FAILURE";
}
let y = doWork2();  // number | string;

what to do with declaration emitter

const FAILURE = "FAILURE"; 

emits a declaration file as:

declare const FAILURE: "FAILURE"; 

which is semantically different from the original, since the original has a fresh "FAILURE" type, that widens, but the second does not widen.

  • this is only applicable for numeric and string literal types, and not enums or booleans.
    so:

    const t: true = true;
    let x = t; // x is a boolean still

    Options:

  • allow initialization in constant declarations in ambient context.. e.g.

declare const FAILURE  = "FAILURE";
  • Q: is this too much for users to think about when writing a .d.ts?
  • A: if you want to expose the value of a constant, add it as an initializer, other wise, it is just a symbolic string
  • Q: What about function return types
  • A: we always widen for these, so no confusion
  • widen when writing to the .d.ts, e.g.
declare const FAILURE: string;
  • Seems like a fine approach
  • can always allow initializers later on.

Widening literal types for properties

  • Issue TS2345 Error when using string literal types in array.map #11054
  • Now that we add literal freshness, do we need to widen on property assignment?
  • Can we just do what we do for null and undefined?
  • in this example a deeper issue is that we do not use return type as inference position
    • we have heard this multiple times. we should try this out first
  • this is the same as:
    ts let x = { type: "folder" }; let a: FolderContentItem = x; // Error today anyways
    similarly a const would not work:
    ts const x = { type: "folder" }; let a: FolderContentItem = x; // Still an error

Strict relationship for literal types (#10120)

  • < and > do not make much sense to be that strict. you should be able to compare 1 > 2.
  • === and == do make sense. we know that true === false is guaranteed to fail all the time.

proposal:

  • for < like operators, widen the literal types to thier base types before doing the check.
@mhegazy mhegazy added the Design Notes Notes from our design meetings label Sep 23, 2016
@DanielRosenwasser
Copy link
Member

What is the point of symbolic names for constants if they don't stick around in a .d.ts?

@mhegazy
Copy link
Contributor Author

mhegazy commented Sep 23, 2016

The names stay, the question is about the values. If they are infected should be treated like the explicit ones, now that we are treating them differently.

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Sep 24, 2016

What I mean is, we've said we want to have literal types "stick" for constants because we believe that they are useful as symbolic variables for people to use. If the declaration emitter won't even respect that, there's no point to writing a library in that style because they'll just have to write const FAILURE: "FAILURE" = "FAILURE" anyway. For self-contained codebases, this might be a win, but this doesn't do much if you're writing a library.

@mhegazy
Copy link
Contributor Author

mhegazy commented Sep 24, 2016

But there is a difference, in the proposal above, between a const with no type annotation and one with a type annotation.

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Sep 24, 2016

Right, in the above proposal you widen for a constant, unless the type is already written out. But that removes the utility of even keeping string literals around for constants because you have to specifically write out the literal type again. You're not much better off than you were in the old contextual typing world.

@mhegazy
Copy link
Contributor Author

mhegazy commented Sep 26, 2016

seems reasonable.

@mhegazy mhegazy closed this as completed Sep 26, 2016
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 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

2 participants