ฉันจะสร้างองค์ประกอบ React“ If” ที่ทำหน้าที่เหมือนจริง“ if” ใน typescript ได้อย่างไร


11

ฉันสร้าง<If />ส่วนประกอบฟังก์ชันอย่างง่ายโดยใช้ React:

import React, { ReactElement } from "react";

interface Props {
    condition: boolean;
    comment?: any;
}

export function If(props: React.PropsWithChildren<Props>): ReactElement | null {
    if (props.condition) {
        return <>{props.children}</>;
    }

    return null;
}

มันช่วยให้ฉันเขียนรหัสทำความสะอาดเช่น:

render() {

    ...
    <If condition={truthy}>
       presnet if truthy
    </If>
    ...

ในกรณีส่วนใหญ่มันใช้งานได้ดี แต่เมื่อฉันต้องการตรวจสอบว่าตัวแปรที่กำหนดไม่ได้ถูกกำหนดและผ่านมันเป็นคุณสมบัติมันจะกลายเป็นปัญหา ฉันจะให้ตัวอย่าง:

สมมติว่าฉันมีองค์ประกอบที่เรียกว่า<Animal />ซึ่งมีอุปกรณ์ประกอบฉากต่อไปนี้:

interface AnimalProps {
  animal: Animal;
}

และตอนนี้ฉันมีองค์ประกอบอื่นที่แสดงผล DOM ต่อไปนี้:

const animal: Animal | undefined = ...;

return (
  <If condition={animal !== undefined} comment="if animal is defined, then present it">
    <Animal animal={animal} /> // <-- Error! expected Animal, but got Animal | undefined
  </If>
);

ตามที่ฉันแสดงความคิดเห็นแม้ว่าในความเป็นจริงแล้วสัตว์ไม่ได้ถูกกำหนด แต่ฉันก็ไม่มีทางที่จะบอก typescript ว่าฉันได้ตรวจสอบแล้ว การยืนยันanimal!จะได้ผล แต่นั่นไม่ใช่สิ่งที่ฉันกำลังมองหา

ความคิดใด ๆ


1
ไม่แน่ใจว่ามันเป็นไปได้ใน typescript ที่จะบอกเขาว่าคุณได้ตรวจสอบความปลอดภัยเป็นโมฆะแล้ว อาจ{animal !== undefined && <Anibal animal={animal} />}จะใช้ได้
Olivier Boissé

1
การหล่อใช้งานได้หรือไม่ <Animal animal={animal as Animal} />
พอล

@ OlivierBoisséฉันถูก จำกัด ให้ใช้ไวยากรณ์นั้น
Eliya Cohen

@ พอลใช่ แต่จะไม่คล้ายกับใส่ "!" ในที่สุด?
Eliya Cohen

คำตอบ:


3

ดูเหมือนเป็นไปไม่ได้

เหตุผล: ถ้าเราเปลี่ยนเนื้อหาIfขององค์ประกอบจาก

if (props.condition) {
  ...
}

มันตรงกันข้าม

if (!props.condition) {
  ...
}

คุณจะพบว่าเวลานี้คุณต้องการให้ประเภทการประมวลผลแตกต่างกันในทางตรงกันข้าม

  <If condition={animal === undefined} comment="if animal is defined, then present it">
    <Animal animal={animal} /> // <-- Error! expected Animal, but got Animal | undefined
  </If>

ซึ่งหมายความว่ามันไม่เป็นอิสระนำไปสู่ข้อสรุปว่ามันเป็นไปไม่ได้ที่จะทำให้เกิดความแตกต่างในสภาพเช่นนี้โดยไม่ต้องสัมผัสทั้งสององค์ประกอบ


ฉันไม่แน่ใจว่าวิธีใดดีที่สุด แต่นี่คือหนึ่งในความคิดของฉัน

คุณสามารถกำหนดAnimal component's อุปกรณ์ประกอบฉากanimalกับ typescript ของ
ประเภทเงื่อนไขการจำหน่าย : NonNullable

เอกสาร

type T34 = NonNullable<string | number | undefined>;  // string | number

การใช้

interface AnimalProps {
  // Before
  animal: Animal;
  // After
  animal: NonNullable<Animal>;
}

มันไม่ได้ถูกสร้างขึ้นโดยIfเงื่อนไขของส่วนประกอบ แต่เนื่องจากคุณใช้child componentภายในเงื่อนไขนั้นเท่านั้นจึงมีความรู้สึกที่จะออกแบบchild componentอุปกรณ์ประกอบฉากเป็นnone nullable, ภายใต้เงื่อนไขที่

พิมพ์ทำประกอบด้วยAnimalundefined


ฉันไม่แน่ใจว่ามันแก้ปัญหาของฉันได้อย่างไร องค์ประกอบสัตว์มีอะไรที่เกี่ยวข้องกับองค์ประกอบถ้า ไม่ควรปรับตัวเองให้เข้ากับองค์ประกอบ If นอกจากนี้ฉันไม่แน่ใจว่า NonNullable มีส่วนเกี่ยวข้องกับปัญหาของฉันอย่างไร
Eliya Cohen

@EliyaCohen อัปเดตสิ่งใดบ้างที่จำเป็นต้องต่อท้ายสำหรับคำตอบนี้
keikai

ฉันได้คัดค้านคำตอบของคุณแม้ว่าฉันจะไม่สามารถยอมรับได้เพราะมันไม่ใช่ทางออก อาจจะได้รับการแก้ไขในอนาคตเมื่อ TS และ React ทำสิ่งนี้ให้เป็นไปได้
Eliya Cohen

1

คำตอบสั้น ๆ

คุณทำไม่ได้

เมื่อคุณกำหนดanimalเป็นAnimal | undefinedวิธีเดียวที่จะลบออกundefinedก็คือสร้างยามหรือแต่งใหม่animalเป็นอย่างอื่น คุณซ่อนประเภทยามในทรัพย์สินสภาพของคุณและ typescript มีวิธีการของการรู้สิ่งที่เกิดขึ้นไม่มีดังนั้นจึงไม่สามารถทราบได้ว่าคุณกำลังเลือกระหว่างและAnimal คุณจะต้องโยนมันทิ้งหรือการใช้งานundefined!

พิจารณาแม้ว่า: สิ่งนี้อาจรู้สึกสะอาด แต่มันสร้างรหัสที่จำเป็นต้องมีความเข้าใจและการบำรุงรักษาบางทีอาจจะมีคนอื่นลงมาที่บรรทัด ในสาระสำคัญคุณกำลังสร้างภาษาใหม่ที่ทำจากส่วนประกอบ React ที่บางคนจะต้องเรียนรู้เพิ่มเติมจาก TypeScript

วิธีอื่นในการส่งออกตามเงื่อนไข JSX คือการกำหนดตัวแปรในrenderที่มีเนื้อหาตามเงื่อนไขของคุณเช่น

render() {
  const conditionalComponent = condition ? <Component/> : null;

  return (
    <Zoo>
      { conditionalComponent }
    </Zoo>
  );
}

นี่เป็นวิธีมาตรฐานที่นักพัฒนาซอฟต์แวร์คนอื่นจะจดจำได้ทันทีและไม่ต้องค้นหา


0

ด้วยการใช้การโทรกลับเรนเดอร์ฉันสามารถพิมพ์ได้ว่าพารามิเตอร์ส่งคืนไม่เป็นโมฆะ

ฉันไม่สามารถแก้ไขIfองค์ประกอบดั้งเดิมของคุณได้เนื่องจากฉันไม่รู้ว่าอะไรที่คุณconditionยืนยันและสิ่งที่ตัวแปรนั้นยืนยันเช่นcondition={animal !== undefined || true}

น่าเสียดายที่ฉันสร้างส่วนประกอบใหม่IsDefinedเพื่อจัดการกับกรณีนี้:

interface IsDefinedProps<T> {
  check: T;
  children: (defined: NonNullable<T>) => JSX.Element;
}

function nonNullable<T>(value: T): value is NonNullable<T> {
  return value !== undefined || value !== null;
}

function IsDefined({ children, check }: IsDefinedProps<T>) {
  return nonNullable(check) ? children(check) : null;
}

แสดงให้เห็นว่าchildrenจะมีการเรียกกลับซึ่งจะผ่าน NonNullable ประเภท T checkซึ่งเป็นชนิดเดียวกับ

ด้วยสิ่งนี้เราจะได้รับการเรียกกลับที่แสดงผลซึ่งจะถูกส่งผ่านตัวแปรที่ตรวจสอบเป็นโมฆะ

  const aDefined: string | undefined = mapping.a;
  const bUndefined: string | undefined = mapping.b;

  return (
    <div className="App">
      <IsDefined check={aDefined}>
        {aDefined => <DoSomething message={aDefined} />} // is defined and renders
      </IsDefined>
      <IsDefined check={bUndefined}>
        {bUndefined => <DoSomething message={bUndefined} />} // is undefined and doesn't render
      </IsDefined>
    </div>
  );

ฉันมีตัวอย่างการทำงานที่นี่https://codesandbox.io/s/blazing-pine-2t4sm


นั่นเป็นวิธีการที่ดี แต่น่าเสียดายที่มันเอาชนะจุดประสงค์ทั้งหมดของการใช้Ifองค์ประกอบ (ดังนั้นมันจึงดูสะอาด)
Eliya Cohen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.