strictNullChecksãæå¹ã«ãããšãçŸåšãããã©ã«ãã®ããããã£ãé©åã«æ©èœããŠããªãããã§ãã äŸãã°ïŒ
interface TestProps { x?: number}
class Test extends React.Component<TestProps, null> {
static defaultProps = {x: 5};
render() {
const x: number = this.props.x;
return <p>{x}</p>;
}
}
error TS2322: Type 'number | undefined' is not assignable to type 'number'
ã®ãšã©ãŒã¯ãå®è¡æã«æ©èœããããšãä¿èšŒãããŠããŸããã
çŸåšãdefaultPropsãšPropsã¯åžžã«åãã¿ã€ããšããŠæ±ãããŠããããã«èŠããŸãããPropsã®ãªãã·ã§ã³ãã£ãŒã«ãã¯DefaultPropsã®å¿ é å€ã§äžæžããããå¿ èŠããããããå®éã«ã¯ã»ãšãã©åãã¿ã€ãã§ã¯ãããŸããã
次ã®ãããªãã®ããã£ãå Žåã¯ã©ããªããŸãã...
class ComponentWithDefaultProps<P, D, S> {
props: P & D & {children?: React.Children};
}
ããã¯ãå°éå ·ã®ã¿ã€ããé€ããŠãæ¢åã®React.Componentã¿ã€ãã³ã°ãšåãã§ããïŒ
ããã©ã«ãã®å°éå ·ã¯å®è¡æã«èšå®ãããã®ã§ãåã¢ãµãŒã·ã§ã³ä»¥å€ã«ãããããŸãåŠçããæ¹æ³ããããã©ããã¯ããããŸããã ïŒãã¡ãããå³å¯ãªnullãã§ãã¯ããã€ã§ãç¡å¹ã«ããããšãã§ããŸããïŒ
ãããããªãã®äŸã§ãããåé¿ããããšãã§ãããããããªãæ¹æ³ã§ãïŒ
interface TestProps { x?: number}
class Test extends React.Component<TestProps, null> {
static defaultProps = {x: 5};
render() {
const x: number = (this.props.x as number);
return <p>{x}</p>;
}
}
https://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertionsãåç §ããŠãã ãã
ãããããåªé ã«åŠçããæ¹æ³ãããã°ãç§ã¯ãããèããŠã¿ããã§ãã
å 責äºé ïŒç§ã¯TypeScriptãçŽ3æ¥é䜿çšããŠããŸãããç²ããŠããŠãããããäœã«ã€ããŠè©±ããŠããã®ãããããŸããã
3ã€ã®ãžã§ããªãã¯åå®çŸ©ãå«ãããã«åå®çŸ©ãã¡ã€ã«ãæŽæ°ãããš+1000ã
ããã¯ã以åã¯---strictNullChecks
ããªããŠãåé¡ãããŸããã§ããããä»ã§ã¯å€ãã®ã³ã³ããŒãã³ãã¯ã©ã¹ã§ééããªãåé¡ã«ãªããŸãã
å³å¯ãªnullåãã§ãã¯ã®æ§è³ªã«ãããFlowãåæ§ã®ã¯ã©ã¹å®è£
ãå®è£
ããŸãã
https://github.com/facebook/flow/blob/master/lib/react.js#L16
https://github.com/facebook/flow/blob/master/lib/react.js#L104 -L105
3çªç®ã®ãžã§ããªãã¯ãè¿œå ããããã«https://github.com/Microsoft/TypeScript/issues/2175ã解決ãããã®ãåŸ
ã€ä»¥å€ã¯ãããã«ã¯å€ãã®ãªãã·ã§ã³ããªãããã§ãã
ãã®ãããªïŒé倧ãªïŒå€æŽïŒã€ãŸãclass Component<P, S, D>
ïŒãã¬ãã¥ãŒã¢ã«ãã£ãŠæ¿èªãããããšã¯ãªããšæããŸãã
@johnnyreilly @bbenezech @pzavolinskyçããã¯ããã«ã€ããŠæèŠããããŸããïŒ
@ r00gerã¯åæããŸããã å®çŸ©ãå€æŽããããšã¯ããŸãã«ãç Žå£çã§ãã
Partial
ã®äœ¿çšãæ€èšãã人ã¯ããŸããïŒ
ã®ããã«ïŒ
interface ComponentClass<P> {
- defaultProps?: P;
+ defaultProps?: Partial<P>;
}
äžèšã®Partial
ã®ãã®ãæ°ã«ããªãã§ãã ããã
éšåçã¯ãéšåçãªpropTypesåé¡ã宣èšããæ¹æ³ã®ã¿ã解決ããŸãã render
ã®å
éšã§ã¯ã lastName
ã¯ãŸã ã¿ã€ãstring | undefined
ã§ãã ãããåé¿ããã«ã¯ã以äžã«ç€ºãããã«ã as
ãŸãã¯!
ã䜿çšããŠæååããã£ã¹ãããå¿
èŠããããŸãã ããã¯æ©èœããŸãããçæ³çã§ã¯ãããŸããã
interface IUser {
firstName: string
lastName?: string
}
export class User extends React.Component<IUser, {}> {
public static defaultProps: Partial<IUser> = {
lastName: 'None',
}
public render () {
const { firstName, lastName } = this.props
// error
lastName.toUpperCase()
return (
<div>{firstName} {lastName}</div>
)
}
}
TSã䜿ãå§ããã°ããã§ãã ç§ã¯äœãã足ããªãã®ã§ããïŒ
誰ããtypesãšdefaultPropsã®è¯ã解決çãæã£ãŠãããªããç§ã¯ãã¹ãŠã®è³ã§ãã çŸåšããããè¡ã£ãŠããŸãã
interface Props {
firstName: string;
lastName?: string;
}
interface DefaultProps {
lastName: string;
}
type PropsWithDefaults = Props & DefaultProps;
export class User extends React.Component<Props> {
public static defaultProps: DefaultProps = {
lastName: 'None',
}
public render () {
const { firstName, lastName } = this.props as PropsWithDefaults;
return (
<div>{firstName} {lastName}</div>
)
}
}
+1
ç§ã¯çŸåšãã®åé¡ãšæŠã£ãŠããŸãã
+1
+1
3çªç®ã®ã¿ã€ãã®ãã©ã¡ãŒã¿ãŒãè¿œå ããããšã«å ããŠãããã©ã«ãã®å°éå ·ã«å¯ŸããŠå°éå ·ãæ¯èŒããæ©èœãå¿ èŠã«ãªããŸãã 幞ããªããšã«ãTS 2.4ã®æç¹ã§ããããå¯èœã«ãªããŸããã https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-319495340ãåç §ããŠãã ãã
IMHOã3çªç®ã®ãã©ã¡ãŒã¿ãŒãè¿œå ããããšã¯å€§ããããšã§ã¯ãããŸããããŸããFlowããŒã ã¯ãããç¥ã£ãŠãããæè¿ãããè¯ããã®ã«å€æŽããŸããã ãã®ãããªããšãã©ã®ããã«åŠçããããç¥ãããšã¯ãã¿ã€ããã§ãã«ãŒã®è²¬ä»»ã§ããã¯ãã§ãã
誀解ããªãã§ãã ãããç§ã¯Typescriptã倧奜ãã§ãããFlow 0.53以éãReactéçºã«ã¯åªããŠãããšèšããããåŸãŸããhttps://medium.com/flow-type/even-better-support-for-react-in-flow- 25b0a3485627
@Hotell Flowã«ã¯React.Component
ã®3ã€ã®åãã©ã¡ãŒã¿ãŒããããŸã-Flowã«ãªã³ã¯ããMediumã®èšäºããšã«ããµãã¯ã©ã¹ã¢ãããŒã·ã§ã³ããã¯ã©ã¹åãã©ã¡ãŒã¿ãŒãæšæž¬ã§ããŸã-ãã¡ããšããèšèªã¬ãã«ã®æ©èœTSã¯ãµããŒãããŠããŸããããåã¯ãµããŒãããŠããŸãã-宣èšã®èæ
®äºé
AFAIKã
@aldendaniels
ãããŒã«ã¯ãReact.Componentã®3ã€ã®ã¿ã€ããã©ã¡ãŒã¿ãŒããããŸã
ãããã0.53ããåã¯ãã®ããã§ããããçŸåšã¯ããã§ã¯ãããŸãã:) https://github.com/facebook/flow/commit/20a5d7dbf484699b47008656583b57e6016cfa0b#diff -5ca8a047db3f6ee8d65a46bba44712ââ36R29
@Hotellããã確ãã«ïŒ ç§ãèšæ£ããŠãããŠããããšãã
ãã ããTSã«ã¯ãããã©ã«ãã®å°éå ·ã®ã¿ã€ããæšæž¬ããæ¹æ³ã¯ãããŸããã 3ã€ã®ã¿ã€ãã®ãã©ã¡ãŒã¿ãŒã®ã¢ãããŒãã䜿çšãããšãTypeScriptããŒã ããã®ã¢ããã¹ããªãŒã ã®å€æŽããããã¯ããããšãªããæ£ããå ¥åãååŸã§ããå¯èœæ§ããããŸãã
åãã©ã¡ãŒã¿ãšããŠtypeof MyComponent.defaultProps
ãæž¡ããã«ãæšå®ãããåã®éçããããã£ã䜿çšããæ¹æ³ãç¥ã£ãŠããŸããïŒ
ãã®ããŒãã«é¢ãããã¥ãŒã¹ã¯ãããŸããïŒ èª°ããPRãè¡ã£ãŠã3çªç®ã®ã¿ã€ãã®ãã©ã¡ãŒã¿ãŒãè¿œå ãã httpsïŒ //github.com/Microsoft/TypeScript/issues/12215#issuecomment -319495340ã䜿çšããŸããïŒ
è³æã®åé¡ïŒåãåé¡
+1
ç§ãããã«ééããïŒãããé©åã«ä¿®æ£ããããŸã§ïŒ static defaultProps
ã®äœ¿çšãæ§ãã代ããã«ãã«ããŒHOCã䜿çšããããšãéžæããŸããã
ãã¡ã€ã«components / helpers / withDefaults.tsx ïŒ
import * as React from 'react'
export interface ComponentDefaulter<DP> {
<P extends {[key in keyof DP]?: any}>(Component: React.ComponentType<P>): React.ComponentType<
Omit<P, keyof DP> & // Mandate all properties in P and not in DP
Partial<Pick<P, keyof DP>> // Accept all properties from P that are in DP, but use type from P
>
}
export default function withDefaults<DP>(defaultProps: DP): ComponentDefaulter<DP> {
return Component => props => <Component {...defaultProps} {...props}/>
}
ä»ç§ã¯äœ¿çšããããšãã§ããŸãïŒ
ãã¡ã€ã«components / Button.tsx ïŒ
import * as React from 'react'
import withDefaults from './helpers/withDefaults'
export interface ButtonProps {
label: string
onPress: () => any
}
export const defaultProps = {
onPress: () => undefined
}
class Button extends React.Component<ButtonProps> {
// ...
}
export default withDefaults(defaultProps)(Button)
3ã€ã®æœåšçãªæ¬ ç¹ïŒç§ãèããããšãã§ããïŒïŒ
props
ããããã£ããã®æšè«ã«äŸåããããšã¯ã§ããŸãããdefaultProps
ã®ã¿ã€ãã®æé»çãªãã§ãã¯ã¯ãããŸããããããã¯export const defaultProps: Partial<ButtonProps> = {...}
ãæå®ããããšã§ä¿®æ£ã§ããŸãã@vsaarinenã«ãããšãç§ã¯props: Props & DefaultProps
ã§åºæ¬ã¯ã©ã¹ãèšè¿°ããŠããã®ã§ãåºæ¬ã¯ã©ã¹ãæ¡åŒµããã¯ã©ã¹å
šäœã§ã this.props as PropsWithDefaults
$ã䜿çšããã«this.props
ãçŽæ¥äœ¿çšã§ããŸãã
ãã®ãããªïŒ
import * as React from 'react'
export class Component<P = {}, S = {}, DP = {}> extends React.Component<P, S> {
props: Readonly<{ children?: React.ReactNode }> & Readonly<P> & Readonly<DP>
}
export interface Props {
firstName: string
lastName?: string
}
export interface DefaultProps {
lastName: string
}
export class User extends Component<Props, any, DefaultProps> {
render() {
const { firstName, lastName } = this.props
// no error
return (
<div>{firstName} {lastName.toUpperCase()}</div>
)
}
}
å®éã«ã¯@ qiu8310ã¯å®å šã«ã¯æ©èœããŸããã§ããããããã©ã«ãã®å°éå ·ããªãã·ã§ã³ã§ã¯ãªãããšã«ã€ããŠã³ãŒã«ãµã€ããå«ã¶ãšããåé¡ããŸã ãããŸããã 埮調æŽã§åäœããããã«ãªããŸãã
import * as React from 'react'
export class Component<P = {}, S = {}, DP = {}> extends React.Component<P, S> {
// Cast the props as something where readonly fields are non optional
props = this.props as Readonly<{ children?: React.ReactNode }> & Readonly<P> & Readonly<DP>
}
export interface Props {
firstName: string
lastName?: string
}
export interface DefaultProps {
lastName: string
}
export class User extends Component<Props, any, DefaultProps> {
render() {
const { firstName, lastName } = this.props
// no error
return (
<div>{firstName} {lastName.toUpperCase()}</div>
)
}
}
ç§ã¯3çªç®ã®ãžã§ããªãã¯ã§éãã§ã @ qiu8310ã®ææ¡ã«äŒŒããã®ãæã£ãŠããŸããïŒ
// ComponentWithDefaultProps.ts
import * as React from "react";
export declare class ComponentWithDefaultProps<P, S, DP extends Partial<P>> extends React.Component<P & DP, S> {}
type redirected<P, S, DP> = ComponentWithDefaultProps<P, S, DP>;
const redirected: typeof ComponentWithDefaultProps = React.Component as any;
export const Component = redirected;
// User.ts
import { Component } from "ComponentWithDefaultProps";
export interface Props {
firstName: string
lastName?: string
}
export interface DefaultProps {
lastName: string
}
export class User extends Component<Props, {}, DefaultProps> {
public render() {
const { firstName, lastName } = this.props;
return <div>{firstName} {lastName.toUpperCase()}</div>;
}
}
ãã ãããããã®ã¢ãããŒãïŒç§ã®ã¢ãããŒããšäžèšã®ã¢ãããŒãïŒã®äž¡æ¹ãããã倧ããªåé¡ãåŒãèµ·ãããŸãã ç§ã®äŸã§ã¯ãäœæãããã³ã³ããŒãã³ãã®ã¿ã€ãããããŸãã
User: React.ComponentClass<P & DP>
User["props"]: Readonly<{ children?: React.ReactNode }> & Readonly<P & DP>
ã©ãããã User
ã®ã€ã³ã¿ãŒãã§ãŒã¹ãééã£ãŠããŸãã React.ComponentClass<P & DP>
ã¯ã lastName
ãå¿
èŠã§ããããšãæå³ããŸãã
<User firstName="" />;
// ~~~~~~~~~~~~ Property 'lastName' is missing...
@ qiu8310ã®äŸã§ã¯ãã¿ã€ããç°ãªããŸãã
User: React.ComponentClass<P>
User["props"]: Readonly<{ children?: React.ReactNode }> & Readonly<P> & Readonly<DP>
ãã ãã tsc
ã®JSXãã§ãã¯ã¯props
'ã¿ã€ãã«åºã¥ããŠãããããåãJSXã§åããšã©ãŒãçºçããŸãã
<User firstName="John" />;
// ~~~~~~~~~~~~~~~~ Property 'lastName' is missing...
é¢çœãã®ã¯ã <User firstName="John" />
ãReact.createElement(User, {firstName: "John"})
ã«å€æãããŠããããšã§ããããã¯ãæå¹ãªTypeScriptã«ãªããŸãã ãã®å Žåãåãã§ãã¯ã¯ComponentClass
ã®æåã®åãã©ã¡ãŒã¿ãŒã«äŸåããããã
<User firstName="Jonh" />; // doesn't work, but
React.createElement(User, { firstName: "John" }); // works
ã芧ã®ãšããã3çªç®ã®ãžã§ããªãã¯ããã£ããšããŠããæ£ããã€ã³ã¿ãŒãã§ã€ã¹ã§ã³ã³ããŒãã³ãããšã¯ã¹ããŒãããã«ã¯ãå¥ã®ããªãã¯ãè¿œå ããå¿ èŠããããŸãã
export const User = class extends Component<Props, {}, DefaultProps> {
// ...
} as React.ComponentClass<Props>;
<User firstName="Jonh" />; // works
ãããã£ãŠã3çªç®ã®ãžã§ããªãã¯ãæã£ãŠããããšã¯ããŸãæå³ããããŸããã
React
ã®å®çŸ©ã«ããŒãžã§ããè¯ã解決çã¯ãªãããã§ããä»ã®ãšããã ComponentWithDefaultProps
ã䜿çšãããšã¯ã¹ããŒããããã³ã³ããŒãã³ãã®ã¿ã€ããã¢ãµãŒãããããšã«åºå·ããŠããŸãã
export interface DefaultProps {
lastName: string;
}
export interface Props extends Partial<DefaultProps> {
firstName: string;
}
export type PropsWithDefault = Props & DefaultProps;
export const User: as React.ComponentClass<Props> =
class extends React.Component<PropsWithDefault> {
render() {
// no error
return <div>
{this.props.firstName}
{this.props.lastName.toUpperCase()}
</div>;
}
};
// Note, we've assigned `React.Component<PropsWithDefault>` to `React.ComponentClass<Props>`
ãããšã¯å¥ã«ãã³ã³ããŒãã³ãã®ã¡ãœããã§this.props
ã¿ã€ãã®ãã¹ãŠã®äœ¿çšæ³ãã¢ãµãŒãã§ããŸãïŒããšãã°ã const { lastName } = this.props as Props & DefaultProps
ããŸãã¯this.props.lastName!.toLowerCase()
ã®ã©ãã§ãæå笊ã䜿çšïŒã
ç§ã¯ãã®è°è«ã«ã€ããŠããã€ãã®äŸãèŠã€ããŸãã-httpsïŒ//github.com/gcanti/typelevel-ts#objectdiff
@riflerããããHOCã¢ãããŒãïŒç§ã¯ãã³ã¬ãŒã¿ã奜ãã§ãïŒã¯ãã°ããã®éããã«ãããŸãããç§ãã¡ã¯å®è¡æã®ãªãŒããŒããããè¿œå ããªã解決çãèãåºãããšãè©Šã¿ãŸã
ããã¯ãã
ããªãã解決çãèŠã€ããããšãé¡ã£ãŠããŸã
äœãé²æ©ã¯ãããŸããïŒ
以äžã¯ã @ r00gerã«ãã£ãŠèšåãããææ³ã®ããªãšãŒã·ã§ã³ã§ãã
interface IUser {
name: string;
}
const User = class extends React.Component<IUser> {
public static defaultProps: IUser = {name: "Foo"}
public render() {
return <div>{this.props.name}</div>;
}
} as React.ComponentClass<Partial<IUser>>;
React.createElement(User, {}); // no error, will output "<div>Foo</div>"
äžèšã®ã¹ããããã䜿çšããŠãæ©èœããŸãããå¿åã¯ã©ã¹ã«ãªããããUserã§éçããããã£ã䜿çšã§ããªããªããŸãã ããããŒãªè§£æ±ºçã¯ã次ã®ããã«ã¯ã©ã¹åãã·ã£ããŠã€ã³ã°ããããšã§ãã
// tslint:disable-next-line:no-shadowed-variable
const User = class User extends React.Component<IUser>
ããã§ãã¯ã©ã¹å ã§ãã©ã€ããŒãéçãã£ãŒã«ãã䜿çšã§ããŸãã ãããªãã¯ã¹ã¿ãã£ãã¯ã¯ãŸã 䜿çšã§ããŸããã ãŸããtslintãæ¶é³ããå¿ èŠãããããšã«æ³šæããŠãã ããã
TS 2.8ã®æç¹ã§ã Exclude
ã¿ã€ããå
¬åŒã«ãµããŒããããŠããããšãèšåãã䟡å€ããããšæããŸããã
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
https://github.com/Microsoft/TypeScript/pull/21847ãåç §ããŠãã ããã
ãããã£ãŠãå¿
èŠãªã®ã¯React.createElement()
ã§ã Props
ã®ä»£ããã«æ¬¡ã®ãã®ãèŠæ±ããããšã§ãã
Omit<Props, keyof DefaultProps>
å¯äžã®åé¡ã¯ãReact宣èšã«ã¯DefaultProps
åããªãããšã§ãããã®ããã«ã¯ã3çªç®ã®åãã©ã¡ãŒã¿ãŒããŸãã¯èšèªæ©èœãšããŠéçã¡ã³ããŒã®åãæšæž¬ããæ©èœãå¿
èŠã§ãã
ãã®éãç§ãã¡ã¯æ¬¡ã®ããšãè¡ã£ãŠããŸããã
/**
* The Create type allow components to implement a strongly thed create() function
* that alows the caller to omit props with defaults even though the component expects
* all props to be populated. The TypeScript React typings do not natively support these.
*/
export type Create<C extends BaseComponent<any, any>, D extends {} = {}> = (
props?: typeHelpers.ObjectDiff<C['props'], D> & React.ClassAttributes<C>,
...children: React.ReactNode[]
) => React.ComponentElement<any, any>;
export interface DomPropsType {
domProps?: domProps.DomProps;
}
export class BaseComponent<P, S = {}> extends React.Component<P & DomPropsType, S> {
static create(props?: object, ...children: React.ReactNode[]) {
return React.createElement(this, props, ...children);
}
constructor(props: P & DomPropsType, context?: any) {
...
}
ãããŠããã¹ãŠã®ã³ã³ããŒãã³ãã¯æ¬¡ã®ããã«ãªããŸãã
export class InsertObjectMenu extends BaseComponent<Props, State> {
static create: Create<InsertObjectMenu, typeof InsertObjectMenu.defaultProps>;
static defaultProps = {
promptForImageUpload: true,
};
...
}
æåŸã«ã create
å±æ§ããã¹ãŠã®ã³ã³ããŒãã³ãã§å®£èšãããããã«åŒ·å¶ããlintã«ãŒã«ããããŸãã JSXã¯äœ¿çšããªãããã次ã䜿çšããŸãã
InsertObjectMenu.create({...})
React.createElement()
ã®ä»£ããã«ã
倧èŠæš¡ãªã³ãŒãããŒã¹å šäœã§ãã®ã¢ãããŒãã䜿çšããŠ1幎è¿ãæåããŸããããJSXãæ¡çšããããšèããŠããããããç§ãã¡ã®è¶³ãåŒã£åŒµã£ãŠããŸãã
ãã®ãåçŽãªåé¡ãã«å€ãã®æéãè²»ãããŸããã ããã¯ããã«æ®ããŠãããŸãhttps://medium.com/@martin_hotell/ultimate-react-component-patterns-with-typescript-2-8-82990c516935ð
interface Component<P = {}, S = {}, DP extends Partial<P>=P> extends ComponentLifecycle<P, S> { }
class Component<P, S, DP extends Partial<P> = P> {
constructor(props: P & DP, context?: any);
// We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
// See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
// Also, the ` | S` allows intellisense to not be dumbisense
setState<K extends keyof S>(
state: ((prevState: Readonly<S>, props: P) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
callback?: () => void
): void;
forceUpdate(callBack?: () => void): void;
render(): ReactNode;
// React.Props<T> is now deprecated, which means that the `children`
// property is not available on `P` by default, even though you can
// always pass children as variadic arguments to `createElement`.
// In the future, if we can define its call signature conditionally
// on the existence of `children` in `P`, then we should remove this.
private __externalProps: Readonly<{ children?: ReactNode }> & Readonly<P>;
props: Readonly<{ children?: ReactNode }> & Readonly<P> & DP;
state: Readonly<S>;
context: any;
refs: {
[key: string]: ReactInstance
};
}
class PureComponent<P = {}, S = {}, DP extends Partial<P>=P> extends Component<P, S, P> { }
interface ElementAttributesProperty { __externalProps: {}; }
æåŸã®è¡ã泚ææ·±ãèŠãŠãã ããã
ãã®å€æŽã«ããã
interface Props {
a: string
b?: string
c?: string
}
class Comp extends React.Component<Props, {}, typeof Comp.defaultProps> {
static defaultProps = {
b: ''
}
render() {
const {a, b, c} = this.props
let res = a.concat(b) // ok
let res1 = a.concat(c) //fail
return null
}
}
const res1= <Comp a=''/> // ok
const res3 = <Comp /> // fail
static defaultProps
ã䜿çšããå Žåã«ååŸã§ããæåã®æ¹æ³ã§ãïŒ typeof Comp.defaultProps
ãçç¥ãããå Žåã¯ãtsãã§ãã«ãŒãå€æŽããå¿
èŠããããŸãïŒã
ä»ã®ãªãã·ã§ã³ã¯ããã§ã«èšãããŠããŸã-HOCãåãã£ã¹ãã
ãããhttps://medium.com/@martin_hotell/ultimate-react-component-patterns-with-typescript-2-8-82990c516935ã®ã¢ã€ãã¢ã«åºã¥ãç§ã®ïŒéåžžã«éãïŒè©Šã¿ã§ãïŒ
type ExtractProps<T> = T extends React.ComponentType<infer Q> ? Q : never;
type ExtractDefaultProps<T> = T extends { defaultProps?: infer Q } ? Q : never;
type RequiredProps<P, DP> = Pick<P, Exclude<keyof P, keyof DP>>;
type RequiredAndPartialDefaultProps<RP, DP> = Required<RP> & Partial<DP>;
type ComponentTypeWithDefaultProps<T> =
React.ComponentType<
RequiredAndPartialDefaultProps<
RequiredProps<ExtractProps<T>, ExtractDefaultProps<T>>,
ExtractDefaultProps<T>
>
>;
function withDefaultProps<T extends React.ComponentType<any>>(Comp: T) {
return Comp as ComponentTypeWithDefaultProps<T>;
}
interface IProps {
required: number;
defaulted: number;
}
class Foo extends React.Component<IProps> {
public static defaultProps = {
defaulted: 0,
};
}
// Whichever way you prefer... The former does not require a function call
const FooWithDefaultProps = Foo as ComponentTypeWithDefaultProps<typeof Foo>;
const FooWithDefaultProps = withDefaultProps(Foo);
const f1 = <FooWithDefaultProps />; // error: missing 'required' prop
const f2 = <FooWithDefaultProps defaulted={0} />; // error: missing 'required' prop
const f3 = <FooWithDefaultProps required={0} />; // ok
const f4 = <FooWithDefaultProps required={0} defaulted={0} />; // ok
@decademoon ããã®ãœãªã¥ãŒã·ã§ã³ã@types/react
ã§äœ¿çšã§ããããã§ãããã§ããŸããïŒ ã€ãŸããéåžžã®React.ComponentType
ããœãªã¥ãŒã·ã§ã³ã«çœ®ãæããå Žåã§ãã
ãããããªããå€åããªãã¯PRãäœæããããšãã§ããŸããïŒ
@decademoonããªãã®å®çŸ©ã¯ãããã©ã«ã以å€ã®å°éå ·ãå®éã«ãªãã·ã§ã³ã®ãã£ãŒã«ããå«ãå ŽåãåŠçããŸããã
interface IProps {
required: number;
notRequired?: () => void;
defaulted: number;
}
class Foo extends React.Component<IProps> {
public static defaultProps = {
defaulted: 0,
};
}
ç§ã®å ŽåãRequiredAndPartialDefaultPropsã¿ã€ããå€æŽããŠããRPãããRequiredãã§ã©ããããªãããã«ããŸããã
type RequiredAndPartialDefaultProps<RP, DP> = RP & Partial<DP>;
ãŸã é©åãªè§£æ±ºçããªãããå°ãªããšãNPMã§æ©èœããHOCããªãããšã«é©ããŠããŸãã ç§ãäœããéããŠããªãéãã
çããããã«ã¡ã¯ã èšãããã£ãã®ã§ããããŸã ãã®ã¹ã¬ãããèªãã§ããã®ã§ããã°ã @ JoshuaToenyesãæãææ矩ã§åœ¹ç«ã€èª¬æããããšæããŸãã ããã¯ééããªãåé¡ã§ã¯ãªãã®ã§ããããšã¯äœã®é¢ä¿ããããŸããã ãã®å Žåãåã¢ãµãŒã·ã§ã³ã䜿çšããŸãã
@toiletpatrolã¯å®éã«ã¯ã @ decademoonã®ãœãªã¥ãŒã·ã§ã³ïŒç§ã®ããããªä¿®æ£ãå«ãïŒã¯èªåçã«ããã©ã«ãã®å°éå ·ãããŸãåŠçããŸãã ããã¯ééããªãReactã®DTå®çŸ©ã«ããŒãžããããã¹ãŠã®äººã«æ©èœæšæºãæäŸããããšãã§ããŸãã
@toiletpatrol @RobRendell https://github.com/Microsoft/TypeScript/issues/23812èŠãŸãããïŒ
@vkrolç§ã¯ãããèŠãŸããããæ°æ©èœã®ãªãªãŒã¹ãåŸ ããã«ãä»ããã³ãŒãããŒã¹ã«decademoonã®å®è£ ãããããããããšãã§ããŸãã
ããªãããŒãªã±ãŒã¹ã§ä»ã®ãšãã䜿çšããŠããå¥ã®åé¿çïŒ
const restWithDefaults = { ...Component.defaultProps, ...rest };
return <Component {...restWithDefaults} />;
äœãåé¡ã¯ãªããšæãã®ã§ãããã§ã¯æ±ããç°¡åãªåé¿çãšããŠæ®ããŠãããŸãã
TS3.2ãšreact16.7ã®ã¿ã€ãã³ã°ã§ãããä¿®æ£ãããŠããŸãã éããŠãããã§ããïŒ
@Hotellæçµçã«ã©ã®ããã«åŠçããå¿ èŠããããŸããïŒ ç§ã¯ãŸã ãããæ£ããåäœãããããšãã§ããŸãã
ä»ã®äººã®æéãç¯çŽããããã«ãTypescript3ã®ãªãªãŒã¹ããŒããžã®ãªã³ã¯ã次ã«ç€ºããŸãã
JSXã§ã®defaultPropsã®ãµããŒã
@cbergmillerç³ãèš³ãããŸãããããããã¯TypeScript3.1ã®ãªãªãŒã¹ããŒãã§ãð
React.FunctionComponent
ã§ãåãåé¡ãçºçããŸã
@denieler defaultProps
ãReact.FunctionComponent
$ãšäžç·ã«äœ¿çšããããšã¯ãå§ãããŸããããããã¯èªç¶ãªããšã§ã¯ãããŸããã ããã©ã«ãã®é¢æ°ãã©ã¡ãŒã¿ãŒã䜿çšããããšããå§ãããŸãã
interface HelloProps {
name?: string;
surname?: string;
}
const HelloComponent: React.FunctionComponent<HelloProps> = ({
name = 'John',
surname = 'Smith',
}) => {
return <div>Hello, {name} {surname}!</div>
};
@mgolå°éå
·ãå解ããããªãå Žåãããã©ã«ãã®é¢æ°ãã©ã¡ãŒã¿ãŒãã©ã®ããã«å®çŸ©ããŸããïŒ
ç§ã¯æ¬¡ã®ããã«ãããã©ã«ããã®ããããã£ã®ã¿ãç Žæ£ããããšããèããããŸããã
interface HelloProps {
name?: string;
surname?: string;
}
const HelloComponent: React.FunctionComponent<HelloProps> = ({
name = 'John',
surname = 'Smith',
...props
}) => {
return <div>Hello, {name} {surname}! You are {props.age} years old.</div>
};
ããããå°éå ·ã®äžéšã ããæœåºããã®ã¯æ¥ãã¹ãããšã ãšæããŸãã
@glecetre䜿çšã§ããŸãïŒ
HelloComponent.defaultProps = {
name: 'John',
surname: 'Smith'
}
@Glinkisãé¡ãããŸãã httpsïŒ //github.com/reactjs/rfcs/pull/107/files#diff-20b9b769068a185d90c23b58a2095a9dR184ã«æ³šæããŠãã ããã
@glecetreãªãããªãã¯ãã¹ãŠã®å°éå
·ãå解ããããªãã®ã§ããïŒ defaultProps
ãå®çŸ©ãããããç°¡åã§ãå
¥åãç°¡åã§ãã defaultProps
ã«ãšã³ããªãããå Žåãå¿
èŠãªå°éå
·ã¯ããå¿
èŠãªãå¯èœæ§ããããããå€éšã§äœ¿çšããããã«ãšã¯ã¹ããŒããããšãã¯ã©ã¹ããŒã¹ã®ã³ã³ããŒãã³ãã®å°éå
·ã¿ã€ããåé¡ã«ãªãå¯èœæ§ããããŸãã defaultProps
ã䜿çšããããšãããã©ã¡ãŒã¿ã®ç Žæ£ã§ã¯ãã¹ãŠJavaScriptã§ãããããå°ãäžæè°ã«æããŸãã
æãåèã«ãªãã³ã¡ã³ã
誰ããtypesãšdefaultPropsã®è¯ã解決çãæã£ãŠãããªããç§ã¯ãã¹ãŠã®è³ã§ãã çŸåšããããè¡ã£ãŠããŸãã