@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
์ด ์ค๋ฅ๋ ๋ฐ์ํฉ๋๋ค. 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"
}
}
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
Typescript 3.0.1์์ ๋ค์ ์ค๋จ๋ฉ๋๋ค. ์๋ ํฐ์!