Definitelytyped: تنفيذ الدعائم الافتراضية مع ts 2.0 فحوصات فارغة صارمة

تم إنشاؤها على ٣٠ سبتمبر ٢٠١٦  ·  50تعليقات  ·  مصدر: DefinitelyTyped/DefinitelyTyped

لا يبدو أن الخصائص الافتراضية تعمل بشكل جيد في الوقت الحالي مع تمكين 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.

ماذا لو كان هناك شيء مثل ...

class ComponentWithDefaultProps<P, D, S> {
    props: P & D & {children?: React.Children};
}

مطابق لـ React.Component النوع الموجود باستثناء نوع الدعائم؟

التعليق الأكثر فائدة

إذا كان لدى أي شخص حل جيد للأنواع والعلامات الافتراضية ، فأنا جميعًا آذان صاغية. نقوم حاليًا بعمل هذا:

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>
    )
  }
}

ال 50 كومينتر

نظرًا لأنه يتم تعيين الخاصيات الافتراضية في وقت التشغيل ، فأنا لست متأكدًا مما إذا كانت هناك طريقة للتعامل مع هذا بشكل جيد ، بخلاف تأكيد النوع. (بالطبع ، يمكنك دائمًا تعطيل عمليات التحقق من القيمة الفارغة الصارمة.)

إليك كيف يمكنك الالتفاف حوله في مثالك:

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 لمدة ثلاثة أيام تقريبًا ، فأنا متعب ، وربما ليس لدي أي فكرة عما أتحدث عنه.

+1000 في تحديث ملف تعريف النوع ليشمل ثلاثة تعريفات عامة للنوع.

كان هذا جيدًا بدون ---strictNullChecks ، لكن الآن ، سيكون بالتأكيد مشكلة للعديد من فئات المكونات.

يطبق Flow أيضًا تطبيقًا مشابهًا للفئة بسبب طبيعة التحقق الصارم من النوع الفارغ.
https://github.com/facebook/flow/blob/master/lib/react.js#L16
https://github.com/facebook/flow/blob/master/lib/react.js#L104 -L105

يبدو أنه ليس لدينا الكثير من الخيارات هنا باستثناء انتظار حل https://github.com/Microsoft/TypeScript/issues/2175 لإضافة عام ثالث.
لا أعتقد أنه يمكن للمراجعين الموافقة على مثل هذا التغيير (أعني class Component<P, S, D> ).
johnnyreillybenezech 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. هل فاتني شيء؟

إذا كان لدى أي شخص حل جيد للأنواع والعلامات الافتراضية ، فأنا جميعًا آذان صاغية. نقوم حاليًا بعمل هذا:

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

بالإضافة إلى إضافة معلمة النوع الثالث ، ستحتاج إلى القدرة على تمييز الخاصيات مقابل الدعائم الافتراضية. لحسن الحظ اعتبارًا من TS 2.4 ، أصبح هذا ممكنًا الآن! راجع https://github.com/Microsoft/TypeScript/issues/12215#issuecomment -319495340

إن إضافة IMHO للمعامل الثالث هو أمر كبير لا ، كما علم فريق Flow ذلك ومؤخراً قاموا بتغيير ذلك من أجل فائدة أكبر. يجب أن تكون مسؤولية مدقق النوع معرفة كيفية التعامل مع هذا النوع من الأشياء.

لا تفهموني بشكل خاطئ ، أنا أحب Typescript ، لكن منذ Flow 0.53 يجب أن أقول إنه متفوق في تطوير التفاعل https://medium.com/flow-type/even-better-support-for-react-in-flow- 25b0a3485627

يحتويHotell Flow على ثلاث معلمات من النوع لـ React.Component - لكل مقال متوسط ​​قمت بربطه بـ Flow يمكن أن يستنتج معلمات نوع الفئة من التعليقات التوضيحية للفئة الفرعية - ميزة أنيقة على مستوى اللغة لا تدعم TS ، ولكنها ليست نوعًا - إعلان مقابل أفايك.

تضمين التغريدة

يحتوي Flow على ثلاث معلمات نوع لـ React.Component

كلا ، كان الأمر كذلك قبل 0.53 ، وليس بعد الآن :) https://github.com/facebook/flow/commit/20a5d7dbf484699b47008656583b57e6016cfa0b#diff -5ca8a047db3f6ee8d65a46bba4471236R29

Hotell آه ، أكيد بما فيه الكفاية! شكرا لتصحيح لي.

AFAIK لا توجد طريقة في TS لاستنتاج نوع الدعائم الافتراضية بالرغم من ذلك. باستخدام نهج المعلمات الثلاثة ، من المحتمل أن نتمكن من الحصول على الكتابة الصحيحة دون حظر التغييرات الأولية من فريق TypeScript.

هل تعرف طريقة لاستخدام النوع المستنتج لخاصية ثابتة بدون تمرير typeof MyComponent.defaultProps كمعلمة نوع؟

أي أخبار عن هذا الموضوع؟ هل يقوم شخص ما بإجراء علاقات عامة لإضافة معلمة من النوع الثالث واستخدام https://github.com/Microsoft/TypeScript/issues/12215#issuecomment -319495340؟

قضية التصويت الإيجابي: نفس المشكلة

+1

واجهت هذا أيضًا ، واخترت (حتى يتم إصلاح ذلك بشكل صحيح) الامتناع عن استخدام static defaultProps وبدلاً من ذلك استخدم HOC المساعد:

مكونات الملف / المساعدون / 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}/>
}

الآن يمكنني استخدام:

مكونات الملف / 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)

ثلاثة جوانب سلبية محتملة (يمكنني التفكير فيها):

  1. إنها تتطلب HOC ، ولكن نظرًا لأن هذا نموذج شائع جدًا في عالم React ، فهذا يبدو جيدًا.
  2. يجب أن تعلن الخاصيات كمعامل نوع عام ، ولا يمكنك الاعتماد على الاستدلال من خاصية props .
  3. لا يوجد فحص ضمني لأنواع defaultProps ، ولكن يمكن معالجة ذلك بتحديد export const defaultProps: Partial<ButtonProps> = {...} .

وفقًا لـ vsaarinen ، أكتب فئة أساسية بـ props: Props & DefaultProps ، لذلك يمكن للفصل بأكمله الذي يمتد للفئة الأساسية استخدام this.props مباشرة بدون استخدام this.props as PropsWithDefaults .

مثله:

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>
    )
  }
}

لعبت مع عام ثالث وانتهى بي الأمر بالحصول على شيء مشابه لاقتراح @ 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>

ولكن نفس القطعة من JSX تسبب نفس الخطأ ، لأن شيكات JSX tsc تعتمد على نوع props ' .

<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

كما ترى ، حتى مع وجود عام ثالث لا يزال يتعين علينا إضافة خدعة أخرى لتصدير مكون بواجهة صحيحة:

export const User = class extends Component<Props, {}, DefaultProps> {
    // ...
} as React.ComponentClass<Props>;

<User firstName="Jonh" />; // works

لذا فإن الحصول على عام ثالث لا معنى له.

يبدو أنه لا يوجد حل جيد يمكن دمجه مع تعريف 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>"

سيعمل استخدام المقتطف أعلاه ، لكنك ستفقد القدرة على استخدام الخصائص الثابتة على المستخدم ، لأنه يصبح فئة مجهولة المصدر. سيكون الحل المبتكر هو إخفاء اسم الفئة ، مثل:

// 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 - لهذا نحتاج إما إلى معلمة من النوع الثالث أو القدرة على استنتاج نوع الأعضاء الثابتة كميزة لغة.

في غضون ذلك ، نتعامل مع ما يلي:

/**
 * 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,
  };
  ...
}

أخيرًا ، لدينا قاعدة lint تفرض أن يتم الإعلان عن السمة create على جميع المكونات. نحن لا نستخدم JSX ، لذلك نستخدم:

InsertObjectMenu.create({...})

بدلا من React.createElement() .

لقد استخدمنا هذا النهج عبر قاعدة بيانات كبيرة لما يقرب من عام الآن بنجاح جيد ، لكننا نرغب في اعتماد JSX وهذا ما يعيقنا.

استثمر الكثير من الوقت في هذه "القضية البسيطة". سأترك هذا هنا https://medium.com/@martin_hotell/ultimate -react-component-Pattern-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 (يجب تغيير المدقق ts إذا أردنا حذف typeof Comp.defaultProps ).
خيارات أخرى ، قيل بالفعل - HOC ، اكتب يلقي.

هذه محاولتي (القبيحة جدًا) بناءً على الفكرة من https://medium.com/@martin_hotell/ultimate -react-component-Pattern-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 المعتاد بالحل الخاص بك.
إذا كان الأمر كذلك ، فربما يمكنك إنشاء علاقات عامة؟

decademoon لا يتعامل تعريفك مع الحالة التي تشتمل فيها الدعائم غير الافتراضية فعليًا على حقول اختيارية ، على سبيل المثال

interface IProps {
  required: number;
  notRequired?: () => void;
  defaulted: number;
}

class Foo extends React.Component<IProps> {
  public static defaultProps = {
    defaulted: 0,
  };
}

لقد نجحت في ذلك في حالتي من خلال تغيير نوع RequiredAndPartialDefaultProps لعدم التفاف "RP" مع "مطلوب"

type RequiredAndPartialDefaultProps<RP, DP> = RP & Partial<DP>;

أنا مندهش من عدم وجود حل مناسب حتى الآن أو على الأقل وجود عامل ترتيب أعلى في NPM ؛ إلا إذا فاتني شيء.

مرحبا جميعا. أردت فقط أن أقول ، وإذا كنت لا تزال تقرأ هذا الموضوع: أعتقد أن JoshuaToenyes قدّم التفسير الأكثر فائدةً وذا مغزى. هذه بالتأكيد ليست مشكلة لذا لا علاقة لها بها. استخدم تأكيد النوع في هذه الحالة.

toiletpatrol في الواقع ، حل decademoon (مع تعديلي الطفيف) يتعامل تلقائيًا مع الدعائم الافتراضية على ما يرام. بالتأكيد يمكن دمجها في تعريفات DT لـ React لتوفير معيار الميزة للجميع.

toiletpatrolRobRendell هل رأيته https://github.com/Microsoft/TypeScript/issues/23812؟

vkrol لقد رأيت ذلك ، لكن يمكنني إسقاط تطبيق decademoon في قاعدة الرموز الخاصة بي الآن دون انتظار إصدارات الميزات الجديدة.

حل آخر أستخدمه حاليًا للحالات الصعبة:

const restWithDefaults = { ...Component.defaultProps, ...rest };
return <Component {...restWithDefaults} />;

أعتقد أنه لا يوجد شيء خاطئ في ذلك ، لذلك سأتركه هنا كحل قذر ولكنه بسيط.

TS 3.2 ورسومات الاستجابة 16.7 تعمل على إصلاح ذلك. ممكن نغلق

Hotell كيف يجب التعامل معها في النهاية؟ ما زلت لا أستطيع الحصول على هذا العمل بشكل صحيح

لتوفير بعض الوقت للآخرين ، يوجد هنا ارتباط إلى ملاحظات إصدار الأنواع 3:
دعم العناصر الافتراضية في JSX

cbergmiller أخشى أن هذه ملاحظات إصدار TypeScript 3.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.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات