GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||
GeezerVison is showing github.com — Generic object rest variables and parameters by ahejlsberg · Pull Request #28312 · microsoft/TypeScript Conversation
Member
With this PR we permit rest properties in destructurings of objects of generic types. This effectively implements what is suggested in #10727 (although by different means) and complements our support for generic spread expressions in object literals implemented in #28234. When a destructuring of an object of a generic type includes a rest variable, the type of the rest variable is an instantiation of the function excludeTag<T extends { tag: string }>(obj: T) { let { tag, ...rest } = obj; return rest; // Pick<T, Exclude<keyof T, "tag">> } const taggedPoint = { x: 10, y: 20, tag: "point" }; const point = excludeTag(taggedPoint); // { x: number, y: number } Some additional examples: const sa = Symbol(); const sb = Symbol(); function f1<T extends { [sa]: string, [sb]: number }>(obj: T) { let { [sa]: a, [sb]: b, ...rest } = obj; return rest; // Pick<T, Exclude<keyof T, typeof sa | typeof sb>> } function f2<T, KA extends keyof T, KB extends keyof T>(obj: T, ka: KA, kb: KB) { let { [ka]: a, [kb]: b, ...rest } = obj; return rest; // Pick<T, Exclude<keyof T, KA | KB>> }
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
# Conflicts: # tests/baselines/reference/objectRest.errors.txt # tests/baselines/reference/objectRest.types
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Member
Author
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Wesley Wigham (weswigham)
approved these changes
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe a
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SHould probably remove this
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, but no harm in keeping it.
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactionsUh oh!
There was an error while loading. Please reload this page.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any idea what's going on here? I'm not sure why we stopped issuing the per-property error.
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assumed it was the change in looking up the type of property names.
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's because we previously treated all computed properties as having known (unit type) names, when here they actually have type
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Nathan Shively-Sanders (sandersn)
approved these changes
# Conflicts: # src/compiler/checker.ts
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Contributor
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
| |||||||||||||||||||||||||||||||
There was an error while loading. Please reload this page.
|
Klaus Meinhardt (@ajafff) But |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Veniamin Krol (@vkrol) Let Klaus Meinhardt (@ajafff) While this is correct, I think it’s actually undesired. Most of the motivation for the higher-order definition of spread as intersection was that it’s quite usable, as well as correct [1] for the common case where two disjoint types are spread together (the case here) or the same type is spread into itself. The definition of rest we ended up with is actually more correct, as you note, but it means that it doesn’t have the same assignability behaviour as spread. I think the correct fix here would be to add a simplification rule in assignability checking that says that However, I’m not sure if such a rule would be applicable anywhere else, and I think it would be fiddly to get right since [1] except of course for own-ness, which the compiler doesn’t track well anyway. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
What about following scenario Nathan Shively-Sanders (@sandersn) ( related to react HoC, but the same behaviour happens with raw functions ) Fix: It needs to be casted to original So is this correct behaviour or a bug ? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
As far as I understand the problem, I think it's the same as Veniamin Krol (@vkrol)'s. I'm not sure I understand it, however. If InjectedProps is the type that's related to withCounter, why does counterWannabe have to declare it as a type at all? Shouldn't In other words, why does Of course, given the |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Nathan Shively-Sanders (@sandersn) I wanted to simplify the example by not involving react but I guess that was bad move :D sorry about that. So here is the React HoC example, with comments: update 11/22/18:
import React, { Component } from 'react' import { Counter } from './counter-render-prop' import { Subtract } from '../types' type ExtractFuncArguments<T> = T extends (...args: infer A) => any ? A : never; // get props that Counter injects via children as a function // InjectedProps is gonna be: // { count: number; } & { inc: () => void; dec: () => void; } type InjectedProps = ExtractFuncArguments<Counter['props']['children']>[0]; // withCounter will enhance returned component by ExtendedProps type ExtendedProps = { maxCount?: number }; // P is constrained to InjectedProps as we wanna make sure that wrapped component // implements this props API const withCounter = <P extends InjectedProps>(Cmp: React.ComponentType<P>) => { class WithCounter extends Component< // enhanced component will not include InjectedProps anymore as they are injected within render of this HoC and API surface is gonna be extended by ExtendedProps Subtract<P, InjectedProps> & ExtendedProps > { static displayName = `WithCounter(${Cmp.name})`; render() { const { maxCount, ...passThroughProps } = this.props; return ( // we use Counter which has children as a function API for injecting props <Counter> {(injectedProps) => maxCount && injectedProps.count >= maxCount ? ( <p className="alert alert-danger"> You've reached maximum count! GO HOME {maxCount} </p> ) : ( // here cast to as P is needed otherwise compile error will occur <Cmp {...injectedProps} {...passThroughProps as P} /> ) } </Counter> ); } } return WithCounter; }; // CounterWannabe implement InjectedProps on it's props class CounterWannabe extends Component< InjectedProps & { colorType?: 'primary' | 'secondary' | 'success' } > { render() { const { count, inc, colorType } = this.props; const cssClass = `alert alert-${colorType}`; return ( <div style={{ cursor: 'pointer' }} className={cssClass} onClick={inc}> {count} </div> ); } } // if CounterWannabe would not implement InjectedProps this line would get compile error const ExtendedComponent = withCounter(CounterWannabe); |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Martin Hochel (@Hotell) What's the source of |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I read the intro to HOCs and I think I understand what's going on, although I haven't had a chance to play with the whole example without Counter.
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Sorry about that, it's not really important I should explicitly provide props in that example. 👉 I've updated previous comment type State = typeof initialState type Props = { children: ( props: State & { inc: Counter['handleInc']; dec: Counter['handleDec'] } ) => React.ReactChild count?: number } & typeof defaultProps const initialState = { count: 0 } const defaultProps = { onChange: (value: number) => {} } export class Counter extends Component<Props, State> { static defaultProps = defaultProps render(){ /*...*/ } }
My bad, updated the code above
will produce the same error
Thanks a lot Nathan Shively-Sanders (@sandersn) 💪 |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.