Definitelytyped: 4.4.41์— ๋„์ž…๋œ @types/react-redux์˜ connect() ๋ฌธ์ œ

์— ๋งŒ๋“  2017๋…„ 06์›” 06์ผ  ยท  44์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: DefinitelyTyped/DefinitelyTyped

@types/react-redux ๋ฒ„์ „ 4.4.40์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ์ฝ”๋“œ

import * as React from 'react';
import {connect} from "react-redux";

interface State {
    y: number;
}

// Own properties
interface OP {
    x: number;
}

// State properties
interface SP {
    y: number;
}

function mapStateToProps(state: State, ownProps: OP): OP & SP {
    return {
        x: ownProps.x,
        y: state.y,
    };
}

class TestComp extends React.Component<OP & SP, null> {
    render() {
        return <p>Hello</p>;
    }
}

export default connect(mapStateToProps)(TestComp);

๋‹ค์Œ๊ณผ ๊ฐ™์ด TestComp ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const tc = <TestComp x={42}/>;

์œ„์˜ ๋ฒ„์ „ 4.4.41 ๋ฐ 4.4.42์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

error TS2324: Property 'y' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<OP & SP, ComponentState>> & { children?:...'.

/cc @thasner @seansfkelley @tkqubo @blakeembrey @sandersn @mhegazy @andy-ms @hans-permana

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

Typescript 3.0.1์—์„œ ๋‹ค์‹œ ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค. ์•ˆ๋…• ํ‹ฐ์—”!

๋ชจ๋“  44 ๋Œ“๊ธ€

์ด ์˜ค๋ฅ˜๋„ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. typedef ์ค‘ ํ•˜๋‚˜๊ฐ€ ์‹ค์ˆ˜๋กœ TOwnProps ์™€ TMergedProps / TStateProps ๋ฅผ ๋ฐ”๊พผ ๊ฒƒ์ฒ˜๋Ÿผ ๋Š๊ปด์ง€์ง€๋งŒ index.d.ts ํ”ผ์ƒ์ ์œผ๋กœ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? redux + typescript๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ƒˆ๋กœ์šด ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์‡ผ์Šคํ† ํผ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ›Œ๋ฅญํ•œ ์ž‘์—…์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

@brauliodiez @blakeembrey ์˜ ์ˆ˜์ •์‚ฌํ•ญ #16969๋ฅผ ๋ณ‘ํ•ฉํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•œ ์‹œ๊ฐ„ ์ •๋„ ํ›„์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋„์›€์ด ๋˜๋Š”์ง€ ์•Œ๋ ค์ฃผ์„ธ์š”.

https://github.com/DefinitelyTyped/DefinitelyTyped/pull/16969์˜ ์ˆ˜์ • ์‚ฌํ•ญ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์ด ๋ฌธ์ œ๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ๋ฌธ์ œ๋ฅผ ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“  ๋”๋ฏธ ๊ตฌ์„ฑ ์š”์†Œ์ž…๋‹ˆ๋‹ค.

import * as React from "react"
import { connect, MapStateToProps, MapDispatchToPropsFunction } from "react-redux"


interface RootState {
  globalA: string
  globalB: number
}

interface DumbComponentProps {
  a: string
  b: number
  c?: number
}

const DumbComponent = (props: DumbComponentProps): JSX.Element => {
  return (
    <div>Something: {props.a} {props.b} {props.c}</div>
  )
}

type ConnectedStateProps = Pick<DumbComponentProps, "a" | "b">
type ConnectedOwnProps = Pick<DumbComponentProps, "c">

const mapStateToProps: MapStateToProps<ConnectedStateProps, ConnectedOwnProps> = (
    state: RootState): ConnectedStateProps => {
  return {
    a: state.globalA,
    b: state.globalB
  }
}

const SmartComponent = connect(
  mapStateToProps
)(DumbComponent)

export default SmartComponent

๊ทธ๋Ÿฐ ๋‹ค์Œ ์–ด๋”˜๊ฐ€์—์„œ SmartComponent๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  c๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค(a & b๋Š” ์ƒํƒœ์—์„œ ์˜จ ๊ฒƒ์œผ๋กœ ๊ฐ€์ •๋จ).

...
return (
  <SmartComponent c{2} />
)

๋‚ด๊ฐ€ ์–ป๋Š” ์˜ค๋ฅ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

error TS2322: Type '{ c: 2; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<DumbComponentProps, ComponentState>> & R...'.
  Type '{ c: 2; }' is not assignable to type 'Readonly<DumbComponentProps>'.
    Property 'a' is missing in type '{ c: 2; }'.

VS Code์˜ ์œ ํ˜•์„ ๊ฒ€์‚ฌํ•˜๋ฉด SmartComponent์— ๋Œ€ํ•ด ์ž˜๋ชป๋œ ์œ ํ˜•์„ ์„ ํƒํ•˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. React.ComponentClass<DumbComponentProps> ๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ React.ComponentClass<Pick<DumbComponentProps, "c">> ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค(์ฆ‰, OwnProps๋งŒ ํ—ˆ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ComponentDecorator๊ฐ€ ComponentClass<T> ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ธ ์œ ํ˜•์—์„œ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. T extends TOwnProps ) ... ๊ทธ๋ž˜์„œ ๋ถˆํ–‰ํžˆ๋„ ์™œ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋งคํ•‘๋˜์ง€ ์•Š๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์—ฌ๊ธฐ์„œ ๋ถ„๋ช…ํžˆ ์ž˜๋ชป๋œ ์ผ์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์œ ์ถ”ํ•˜๋Š” ๋‚ด์šฉ์„ ๋‹จ๊ณ„๋ณ„๋กœ ํ‘œ์‹œํ•˜๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

mapDistpachToProps๋Š” ์ด์ œ ์„ ํƒ ์‚ฌํ•ญ์ด ์•„๋‹Œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ดœ์ฐฎ๋‚˜์š” ๋ฒ„๊ทธ์ธ๊ฐ€์š”?

์œ„์˜ ๋‚ด ์˜๊ฒฌ์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ, ์กฐ๊ธˆ ํŒŒํ—ค์นœ ํ›„ - ํ˜„์žฌ ์‹คํŒจํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค(๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๋ ‡๊ฒŒ ํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค). OwnProps๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ถ”์ธกํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: connect()(DumbComponent) ). ๋‚ด ๋ณ€๊ฒฝ ์ง‘ํ•ฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
https://github.com/DefinitelyTyped/DefinitelyTyped/compare/master...ritwik :react-redux/fix-ownprop-inference
์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ฃผ๊ณ  ์‹ถ์ง€๋งŒ typescript๋กœ ๋‚ด ์ง€์‹์˜ ํ•œ๊ณ„์— ๋ถ€๋”ชํžˆ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ๋‚ด ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋‚˜ ์ œ์•ˆ ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์ƒ๊ฐ์ด ์žˆ์œผ๋ฉด ์ด์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ๋ฃจํ”„๋ฅผ ๋‹ซ์œผ๋ฉด - https://github.com/DefinitelyTyped/DefinitelyTyped/pull/17196 ์ด ์šฐ๋ฆฌ ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ๋˜์—ˆ๋‚˜์š”? ํ˜„์žฌ ^5.0.8( IntrinsicAttributes & IntrinsicClassAttributes<Component<Pick ... )์—์„œ ์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์œ ์ผํ•œ ์ฐจ์ด์ ์€ interfaces types ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ˆ„๊ตฌ๋‚˜? ์ด๊ฒƒ์€ ๋ถˆํ–‰ํžˆ๋„ ๋‚˜์—๊ฒŒ ์ง„์ •ํ•œ ์‡ผ ์Šคํ† ํผ์ž…๋‹ˆ๋‹ค ...

@proProbe @types/react-redux , @types/react ๋ฐ redux ๋ฒ„์ „๊ณผ ์˜ค๋ฅ˜๋ฅผ ์žฌํ˜„ํ•˜๋Š” ์ƒ˜ํ”Œ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
๋˜ํ•œ CC ํŒจํ‚ค์ง€ ์ž‘์„ฑ์ž: @tkqubo @thasner @kenzierocks @clayne11 @tansongyang @nicholasboll

๋Šฆ์€ ๋‹ต๋ณ€ ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค! ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์žฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ƒ˜ํ”Œ๋กœ ์ž‘์—…ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๊ฐ‘์ž๊ธฐ ์ด๊ฒƒ์ด @types/react-redux: "^5.0.8"์—์„œ ์ˆ˜์ •๋˜์—ˆ์Œ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜๋„ ๊ณ ๋งˆ์›Œ!

์—ฌ์ „ํžˆ "^5.0.10"์œผ๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. :(

"@types/react": "^15.6.4",
"redux": "3.7.2",
"@types/react-redux": "^5.0.10"

์ฝ”๋“œ ์กฐ๊ฐ์„ ํŒจํ‚ค์ง€ ์ž‘์„ฑ์ž์™€ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ถˆํ–‰ํžˆ๋„ ๊ณต๊ฐœ์ ์œผ๋กœ ๊ณต์œ ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

์œ„์—์„œ ์ œ์•ˆํ•œ ๋Œ€๋กœ 4.4.40์œผ๋กœ ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ์ฆ‰์‹œ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

mapStateToProps์˜ ๋ฐ˜ํ™˜ ๊ฐ’ ์œ ํ˜•๊ณผ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ownProps ์œ ํ˜•์— ๋Œ€ํ•œ ์—ฐ๊ฒฐ์„ ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”ํ•˜์—ฌ ๋‚ด ์ฝ”๋“œ ๊ธฐ๋ฐ˜์—์„œ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ œํ’ˆ ID ๋ชฉ๋ก์œผ๋กœ ๋‚ด ์ œํ’ˆ ๋ชฉ๋ก์„ ํ˜ธ์ถœํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์ปจํ…์ŠคํŠธ์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค.

<ProductList productIDs={productIDs} />

๊ทธ๋ฆฌ๊ณ  mapStateToProps ๋ฅผ ๊ฐ€์ง€๊ณ  ํ•ด๋‹น ID๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ชฉ๋ก์— ํ‘œ์‹œํ•  ์ œํ’ˆ์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

const mapStateToProps = (state: RootState, ownProps: {productIDs: List<UUID>}) => {
  return { products: state.get('products').filter(
    (p: Product) => ownProps.productIDs.contains(p.uuid)) };
};

๋‹ค์Œ๊ณผ ๊ฐ™์ด connect ๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

const ProductList = connect<ProductListProps, void, {productIDs: List<UUID>}>(mapStateToProps)(ProductListComponent);

์•ฝ๊ฐ„์˜ ์กฐ์‚ฌ ํ›„. ๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค. React.Component<,> ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒฝ์šฐ tsconfig.json์— "compilerOptions": { "strict": true } ๋งŒ ์žˆ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Typescript 2.8.x๋Š” ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๊ณ  ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”.

Typescript 3.0.1์—์„œ ๋‹ค์‹œ ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค. ์•ˆ๋…• ํ‹ฐ์—”!

TypeScript 3.2.2์—์„œ๋„ ์ค‘๋‹จ.

์ด ๋ฌธ์ œ์— ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

Typescript 3.2.2๋„ ์ €๋ฅผ ์œ„ํ•ด ๊นจ์กŒ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ connect ์— connect<Props> ์ฃผ์„์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์—ฐ๊ฒฐ์— ์ฃผ์„์„ ๋‹ฌ์•„๋„ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค./

์ €๋„ ๊ฐ™์€ ํ˜„์ƒ์ธ๋ฐ ์—…๋ฐ์ดํŠธ๊ฐ€ ์ „ํ˜€ ์•ˆ๋˜๋‚˜์š”?

TypeScript 3.2.4์—์„œ๋„ ์ค‘๋‹จ.

์ด๊ฒƒ์€ ๊ณง ํ•ด๊ฒฐ๋˜์ง€ ์•Š์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๋ชจ๋“  ์‚ฌ๋žŒ์—๊ฒŒ ์—ฐ๊ฒฐ๋œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ฐ€์ ธ์˜ค๋Š”์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค. redux์—์„œ ์•ฑ ์ƒํƒœ์— ์•ก์„ธ์Šคํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ connect() ํ•จ์ˆ˜๋กœ ์ „ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋™์•ˆ ์ƒํƒœ ๋น„์ €์žฅ ํ•จ์ˆ˜ ๋‚ด๋ณด๋‚ด๊ธฐ์—์„œ ๊ธฐ๋ณธ ํด๋ž˜์Šค ๊ตฌ์„ฑ ์š”์†Œ ๋‚ด๋ณด๋‚ด๊ธฐ๋กœ ์ „ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํŒŒ์ผ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ๋ฒ•์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์•˜์„ ๋•Œ ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

์ž‘๋™ ์ค‘์ž…๋‹ˆ๋‹ค.

์ด ์˜ค๋ฅ˜๋ฅผ ๋กœ์ปฌ์—์„œ ์ตœ์†Œํ•œ ์นจ๋ฌต์‹œํ‚ค๋Š” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

ํ™•์‹คํžˆ OwnProps ๋Œ€ StateProps์˜ ์–ด๋”˜๊ฐ€์— ํ”Œ๋ฆฝํ”Œ๋กญ์ด ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ž์‹์ด ์žˆ๋Š” Redux ์—ฐ๊ฒฐ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ๋Š” ์ด ๋ฌธ์ œ๋ฅผ ๋ณด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ์นจ๋ฌต์‹œํ‚ค๊ธฐ ์œ„ํ•ด ๋‚ด๊ฐ€ ํ•œ ๊ฒƒ์€ <any> ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

export default connect<any>(states, actions)(SomeComponent);

์ž‘์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

export default compose<any>(
  connect(states, actions),
  withStyles(styles)
)(SomeFunctionalComponent);

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์†Œํ’ˆ์„ '์Šค๋งˆํŠธ'/์—ฐ๊ฒฐ๋œ ๊ตฌ์„ฑ ์š”์†Œ์— ์ „๋‹ฌํ•  ๋•Œ ์˜ค๋ฅ˜๊ฐ€ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

ํŽธ์ง‘: ๋ฐฉ๊ธˆ ์Šค๋ ˆ๋“œ๋ฅผ ๋‹ค์‹œ ์ฝ์—ˆ๊ณ  @themodernlife ์˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ์ด ๋” ๋‚˜์€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค(์ฆ‰, Props ์ธํ„ฐํŽ˜์ด์Šค ๋˜๋Š” ์œ ํ˜•์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐ์— ์ฃผ์„์„ ๋‹ฌ๊ฑฐ๋‚˜ ์ž‘์„ฑ).

๊ทธ๊ฒƒ์€ ๋˜ํ•œ ๋ชจ๋“  ์œ ํ˜• ๊ฒ€์‚ฌ์™€ Intellisense๋ฅผ ํŒŒ๊ดดํ•˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ๊ทธ๋ ‡๋‹ค๋ฉด ํƒ€์ดํ•‘์„ ์ถ”๊ฐ€ํ•˜๋Š” ์š”์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? @dcefram

์˜ˆ, ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ์นจ๋ฌต์‹œํ‚ค๊ณ  ์ด๊ฒƒ์ด "์‡ผ ์Šคํ† ํผ"๊ฐ€ ๋˜์ง€ ์•Š๋„๋ก ๋นŒ๋“œํ•˜๋„๋ก ํ—ˆ์šฉํ•˜๋Š” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค(๋˜๋Š” ์ œ ๊ฒฝ์šฐ์—๋Š” ์ˆ˜์ • ์‚ฌํ•ญ์ด ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ TS์—์„œ ๋ชจ๋“  ๊ฒƒ์„ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ์ค‘๋‹จ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด). ). ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ํ•ด๊ฒฐ์ฑ…์ด ์•„๋‹™๋‹ˆ๋‹ค .

์ €๋„ ์ˆ˜์ •์„ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค :)

๋” ๋‚˜์€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด connect ํ˜ธ์ถœ์„ ์ˆ˜๋™์œผ๋กœ ์ž…๋ ฅํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

type StateProps = {
  // Attributes that you want mapped from redux store
}
type DispatchProps = {
  // Dispatch actions
}
type OwnProps = {
  // Other props that component expects when being created
}
type Props = StateProps & DispatchProps & OwnProps;
class ExampleComponent extends React.Component<Props> { /* ... */ }

const mapStateToProps = (state: State, ownProps: OwnProps): StateProps => { /* .. */ }
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => { /* ... */ }

export default connect<StateProps, DispatchProps, OwnProps>
  (mapStateToProps, mapDispatchToProps)(ExampleComponent)

์ด๊ฒƒ์€ ์ƒ์„ฑ๋  ๋•Œ OwnProps ๋ฅผ ์˜ˆ์ƒํ•˜๊ณ  ๋‹ค๋ฅธ ์ƒํƒœ๋‚˜ ๋””์ŠคํŒจ์น˜ ์†Œํ’ˆ์ด ์—†๋Š” ์˜ฌ๋ฐ”๋ฅธ ์—ฐ๊ฒฐ๋œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ถ€์ •์ ์ธ. ์—ฌ์ „ํžˆ ์œ ํ˜•์„ ์œ ์ถ”ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  ์ˆ˜๋™์œผ๋กœ const ๋ฅผ ์ž…๋ ฅํ•œ ๋‹ค์Œ ์ด๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

const connected: React.ComponentType<OwnProps> = connect<StateProps, DispatchProps, OwnProps>(......)(Component);
export default connected;

"@types/react-redux": "7.0.1" ๋ฐ "typescript": "3.4.5"๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ connect()์™€ ๋™์ผํ•œ ๋ฌธ์ œ์— ์ง๋ฉดํ•ฉ๋‹ˆ๋‹ค. ์–ธ๊ธ‰ ๋œ ์†”๋ฃจ์…˜์ด ๋„์›€์ด๋˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. @TroySchmidt ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ์ผ๋ถ€ ์ƒ˜ํ”Œ ์ฝ”๋“œ๊ฐ€ ๋งค์šฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ƒ์œ„ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์ด "์—ฐ๊ฒฐ"์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์•ˆ๋…•ํ•˜์„ธ์š” ๋น„์Šทํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. react-redux๋Š” mapStateToProps์˜ ๋ฐ˜ํ™˜ ๊ฐ’์„ "TInjectedProps"๋กœ ํ•ด์„ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด Omit ๋„์šฐ๋ฏธ @types/react-redux index.d.ts:110 export type InferableComponentEnhancerWithProps ์—์„œ ์ž˜๋ชป๋œ ์ œ์™ธ๊ฐ€ โ€‹โ€‹๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์—ฐ๊ฒฐ ํ•จ์ˆ˜์˜ ์œ ํ˜• ์ •์˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

// connect Redux
export const RCHeader = connect
<IHeaderStateToProps, //returned by mapStateToProps
 {}, // not necessary
 IHeaderProps, // props you want to pass through jsx/tsx
 IHeaderConnectedReduxStateProps, // combined from IHeaderMapStateToProps and IHeaderProps
 {}// not necessary
>(
    (state: ISettingsState ): IHeaderStateToProps => {
        return {
            headerLogoURL: state.settings.headerLogoURL
        }
    },
    undefined,
    undefined,
    { forwardRef: true }
)(Header);
{
  "dependencies": {
    "react": "^16.8.6",
    "react-redux": "^6.0.1",
    "redux": "^4.0.1"
  },
  "devDependencies": {
    "@types/react": "^16.8.17",
    "@types/react-redux": "^7.0.6",
    "react-scripts-ts": "^4.0.8",
    "typescript": "^3.4.5"
  }
}

์ด์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์ตœ๊ทผ์— redux์— connect ๊ฐ€ ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋‹ค๋ฅธ ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  ์†Œํ’ˆ์ด ๋ˆ„๋ฝ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•˜์‹ญ์‹œ์˜ค.

type StateProps = {
  /* some code */
};

type DispatchProps = {
  /* some code */
};

type OwnProps = {
  /* some code */
};

type Props = StateProps & DispatchProps & OwnProps;

const mapStateToProps = (state: IReduxState): StateProps => ({
  /* some code */
});

const mapDispatchToProps = (dispath: Dispatch<AnyAction>): DispatchProps => {
  /* some code */
};

const BaseComponent: React.FC<Props> = (props: Props) => {
  /* some code */
};

export const ConnectedComponent: React.ComponentType<OwnProps> = connect<
  StateProps,
  DispatchProps,
  OwnProps,
  IReduxState
>(
  mapStateToProps,
  mapDispatchToProps
)(BaseComponent);

์ข…์†์„ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

{
  "dependencies": {
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-redux": "^7.1.0",
    "redux": "^4.0.1",
  },
  "devDependencies": {
    "@types/react": "^16.8.22",
    "@types/react-dom": "^16.8.4",
    "@types/react-redux": "^7.1.0",
    "@types/redux": "^3.6.0",
    "typescript": "^3.5.2"
  }
}

๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋ณธ ์œ ํ˜• ์œ ์ถ”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ์ด๋Ÿฌํ•œ ์œ ํ˜•์„ ๋ชจ๋‘ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์ด ์•„๋‹Œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค...

์ด๊ฒƒ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋ฌธ์ œ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. 7.0.1 ๋ฅผ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๊ณ  ์œ ํ˜• ์ถ”๋ก ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ 7.0.2 ๋ฒ„์ „์—์„œ ๋„์ž…๋œ ๊ฒƒ์ด ํ™•์‹คํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋ฅผ ์œ„ํ•ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
@justemit ์€ react ๋ฐ redux์˜ ๋งˆ์ง€๋ง‰ ๋ฒ„์ „์—์„œ ์ž‘๋™ํ•˜๋Š” ์˜ฌ๋ฐ”๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ฒŒ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค.

@justemit ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ๋•๋ถ„์— ๋ฏธ์น˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค ๐Ÿ™Œ

ํŽธ์ง‘: React.FC<Props> ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค ๐Ÿ˜‚

๋‚˜๋Š” ์ด ๋ฌธ์ œ๊ฐ€ @types/react-redux@^7.1.2 ์— ์—ฌ์ „ํžˆ ์‚ด์•„ ์žˆ๊ณ  ์ž˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

const propTypes = {
  foo: PropTypes.number.isRequired,
  bar: PropTypes.func.isRequired
};

// inferring the Props type
interface Props extends PropTypes.InferProps<typeof propTypes> {}
// although doing it explicitly also yields the same result
interface Props {
  foo: number,
  bar: (...args: any[]) => any
}

const Foo = (props : Props) => <></> // EDIT: incorrect way to define functional components
const Foo : React.FC<Props> = (props) => <></> // EDIT: the correct way
//          ^^^^^^^^

Foo.propTypes = propTypes;
/* Foo.defaultProps = {
  foo: 1,
  bar: () => {}
} //*/

const mapStateToProps = (state : any) => ({
  foo: 1
})
const mapDispatchToProps = {
  bar: () => {}
}
const Bar = connect(mapStateToProps, mapDispatchToProps)(Foo)

const Baz = () => <Bar /> // throws an error
Type '{}' is missing the following properties from type 'Readonly<Pick<Pick<Props, never>, never> & Pick<InferProps<{ foo: Validator<number>; bar: Validator<(...args: any[]) => any>; }>, "foo" | "bar">>': foo, bar



md5-e744aa0bac3ac7f45f015259c5597ea9



'ConnectedComponentClass<...>' ์œ ํ˜•์€ 'ComponentType<{}>' ์œ ํ˜•์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
'Readonly<{}>' ์œ ํ˜•์— 'Readonly ์œ ํ˜•์˜ ๋‹ค์Œ ์†์„ฑ์ด ์—†์Šต๋‹ˆ๋‹ค.; ๋ง‰๋Œ€: ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ธฐ<(...์ธ์ˆ˜: ๋ชจ๋“ []) => ๋ชจ๋“ >; }>>': ํ‘ธ, ๋ฐ”

And even if typing everything explicitly helped, I agree with <strong i="16">@alexandrudanpop</strong> that it should be possible to infer those types instead of doing everything manually ๐Ÿค” 

**Edit:** for anyone looking for inspiration for a workaround, I currently resort to explicitly casting using `unknown`:
```ts
// assumes `mapDispatchToProps` is an object, could be a function if used with `ReturnType`
type OwnProps = Omit<Props, keyof ReturnType<typeof mapStateToProps> | keyof mapDispatchToProps>
connect(mapStateToProps, mapDispatchToProps)(Foo) as unknown as React.ComponentType<OwnProps>

์ถ”๋ก ์— ๋„์›€์ด ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ(์—ฌ์ „ํžˆ ์ผ๋ถ€ ์ˆ˜๋™ ์ž‘์—…)์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
@kdmadej ์˜ˆ์ œ์—์„œ ๋ฒ—์–ด๋‚˜๊ธฐ

type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = typeof mapDispatchToProps;
type OwnProps = {
  a: string;
  b: number;
}

type Props = StateProps & DispatchProps & OwnProps;

const Foo = (props : Props) => <></>

const mapStateToProps = (state : any) => ({
  foo: 1
})

const mapDispatchToProps = {
  bar: () => {}
}

export default connect(mapStateToProps, mapDispatchToProps)(Foo)


// In another file
const Baz = () => <Bar /> <-- this should throw error expecting `a` and `b`

๊ทธ๋Ÿฌ๋‚˜ ๋‚ด๊ฐ€ ์ง๋ฉดํ•œ ๋ฌธ์ œ๋Š” OwnProps ๋ฅผ ๋ฏน์Šค์— ์ถ”๊ฐ€ํ•  ๋•Œ์ž…๋‹ˆ๋‹ค. <Bar /> ๋ฅผ ์–ด๋””์—์„œ๋‚˜ ์‚ฌ์šฉํ•˜๋ฉด $ a ๋ฐ b ์†Œํ’ˆ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ด์•ผ ํ•˜์ง€๋งŒ ๊ทธ๋ ‡์ง€ ์•Š๊ณ  ์ •๋ง ์งœ์ฆ์ด ๋‚ฉ๋‹ˆ๋‹ค(๋ง์žฅ๋‚œ ์—†์Œ).

๋‚˜๋Š” ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๊ฒƒ์„ ํ•ด๊ฒฐํ–ˆ๋‹ค.

const ConnectedBar: React.ComponentType<OwnProps> = connect(mapStateToProps, mapDispatchToProps)(Bar);
export default ConnectedBar;

๋˜๋Š” ๋™๋“ฑํ•˜๊ฒŒ

export default connect(mapStateToProps, mapDispatchToProps)(Foo) as React.ComponentType<OwnProps>;

ํ•จ์ˆ˜ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž…๋ ฅํ•˜๊ธฐ ์œ„ํ•ด React.FC<Props> ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค ๐Ÿ˜‰
์›๋ณธ ๊ฒŒ์‹œ๋ฌผ ์„ ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? @alexandrudanpop ์ด ๋งํ–ˆ๋“ฏ์ด ์ผ๋ถ€ ๊ธฐ๋ณธ ์œ ํ˜• ์ถ”๋ก  ๋Œ€์‹  ์ด๋Ÿฌํ•œ ์œ ํ˜•์„ ๋ชจ๋‘ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ์ข‹์€ ์†”๋ฃจ์…˜์ด ์•„๋‹Œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. 7.2.1 ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ ์—ฌ์ „ํžˆ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ๋‹ค๋ฅธ ๊ตฌ์„ฑ ์š”์†Œ์—๋Š” ๋‹ค์Œ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

const connector = connect(mapStateToProps, mapDispatchToProps);
type PropsFromRedux = ConnectedProps<typeof connector>;
type Props = PropsFromRedux & OwnProps;

๊ทธ๋Ÿฌ๋‚˜ ๋ถ€๋ชจ๊ฐ€ ์ผ๋ถ€ ์†Œํ’ˆ์„ ๋ณด๋‚ด๋Š” ๊ฒฝ์šฐ์—๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
npm ์—…๋ฐ์ดํŠธ ํ›„ ๊นจ๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.
๋‚ด ์ˆ˜์ • ์‚ฌํ•ญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
export default connect(mapStateToProps)(ConnectedIntlProvider) as unknown as ComponentType<unknown>;
OwnProps๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์•Œ ์ˆ˜ ์—†์Œ. OwnProps๋งŒ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
export default connect<StateFromProps, null, OwnProps, ApplicationState>(mapStateToProps)(viewWithIntl);

๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
export default connect<StateFromProps, DispatchFromProps, OwnProps, ApplicationState>( mapStateToProps, mapDispatchToProps, )(attachmentFormWithIntel)
๊ทธ๋ฆฌ๊ณ  ์ ‘๋ฏธ์‚ฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
as unknown as ComponentType<OwnProps>;

์‚ฌ์šฉ
"@์œ ํ˜•/๋ฐ˜์‘": "16.9.49",
"@types/react-redux": "^7.1.9",
"typescript": "^4.0.3"
"redux": "^4.0.5",
{
"์ข…์†์„ฑ": {
"๋ฐ˜์‘": "^16.13.1",
"react-dom": "^16.13.1",
"๋ฐ˜์‘ redux": "^7.2.1",
"redux": "^4.0.5",
},
"devDependencies": {
"@types/react": "16.9.49"
"@types/react-dom": "16.9.8",
"@types/react-redux": "^7.1.9",
"typescript": "^4.0.3"
}
}

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰