[[Early thoughts around conditional types]]
- 
Currently have T extends Fooas a type operator that returnstrueorfalse.- Seems very strange as to what that actually means:
declare function foo<T>(x: T, y: T extends string): void; 
- This function takes an x, and ifxis astring,ymust betrueor otherwisefalse.
- Not entirely useful.
 
- Seems very strange as to what that actually means:
- 
Key idea: you want to be able to narrow in the true branch of a conditional type. - Example
type DeepReadonly<T> = T extends any[] ? ReadonlyArray<T[number]> : T extends object ? DeepReadonly<T> : T; 
- Need to be able to know that Tis an array type to actually perform the indexed accessT[number]- 
Could say users need to replace instances of TwithT & any[]- Not correct though - (T & any[])[number]gives youany.
- If we have type unknown = {} | null | undefinedand usedunknown[]might be better?- Eh, gives weird union types.
 
 
- Not correct though - 
- 
Really what you want is to refine the constraint of T.
- 
Idea: T extends Foo, whereextendsis a type operator that augments the constraint ofT.- Kind of like intersecting, more correct and consistent.
- What happens when you stack these together? e.g. T extends Foo extends Bar?- Simplifies to T extends Foo & Bar
 
- Simplifies to 
 
- 
Users could potentially write these types out? - Sure, but not entirely useful; usually would only come out from narrowing in a conditional type.
 
- 
Instantiation? - Instantiate LHS, if it's still generic, remove RHS.
 
- 
What about narrowing in an expression context? function f<T>(x: T) { if (typeof x === "string") { return x; } throw new Error("Gimme string!"); } - The return type here should be T extends string.- 
What about when Tisnumber?
- 
If you verify against the RHS at instantiation, you can get never!
- 
Becomes a matter of... - declaration-site/call-site verification:
 // vvvvvvvvvvvvvv function f<T extends string>(x: T) { /*...*/ } f(100); // nope! - vs use-site verification
 // T extends string -> number extends string -> never let x: never = f(100); x.whoops; // nope 
 
- 
- In a sense, this is sort of related to type predicates!
- Type predicate annotations guarantee a truevalue if a type matches some type.
- This returns a value of a more specific type using information upon instantiation.
 
- Type predicate annotations guarantee a 
 
- The return type here should be 
 
- 
 
- Example
- 
In general, we are trying to decide what is the appropriate behavior for the extendssyntax.- One option is the "is-assignable" operator.
- The other is the "type parameter constraint augmentation" operator
- We want both in the lanugage.
- Could make it context-depenent?
- Could get rid of the "is-assignable" operator, make it part of conditional types.
- Means it's harder to compose with And<T, U>andOr<T, U>.
- But composing doesn't even keep track of the information that's flowed through. e.g.
- And<T extends Foo, T extends Bar> ? /*trueBranch*/ : /*falseBranch*/- We don't have a way of tracking that Tshould be treated asT extends Foo & BarintrueBranch.
 
- We don't have a way of tracking that 
 
 
- Means it's harder to compose with 
- In general, this might be confusing for users.
 
- Could get rid of the "is-assignable" operator, make it part of conditional types.