typescript
GitHub
  • README
  • Давайте Почнемо
    • Why TypeScript
  • JavaScript
    • Equality
    • References
    • Null vs. Undefined
    • this
    • Closure
    • Number
    • Truthy
  • Future JavaScript Now
    • Classes
      • Classes Emit
    • Arrow Functions
    • Rest Parameters
    • let
    • const
    • Destructuring
    • Spread Operator
    • for...of
    • Iterators
    • Template Strings
    • Promise
    • Generators
    • Async Await
  • Проект / Project
    • Контекст компіляції / Compilation Context
      • tsconfig.json
      • Які файли / Which Files?
    • Простори Оголошень / Declaration Spaces
    • Модулі / Modules
      • File Module Details
      • global.d.ts
    • Namespaces
    • Dynamic Import Expressions
  • Node.js QuickStart
  • Browser QuickStart
  • Library QuickStart
  • TypeScript's Type System
    • JS Migration Guide
    • @types
    • Ambient Declarations
      • Declaration Files
      • Variables
    • Interfaces
    • Enums
    • lib.d.ts
    • Functions
    • Callable
    • Type Assertion
    • Freshness
    • Type Guard
    • Literal Types
    • Readonly
    • Generics
    • Type Inference
    • Type Compatibility
    • Never Type
    • Discriminated Unions
    • Index Signatures
    • Moving Types
    • Exception Handling
    • Mixins
  • JSX
    • React
    • Non React JSX
  • Options
    • noImplicitAny
    • strictNullChecks
  • Errors in TypeScript
    • Interpreting Errors
    • Common Errors
  • NPM
  • Testing
    • Jest
    • Cypress
  • Tools
    • Prettier
    • Husky
    • ESLint
    • Changelog
  • TIPs
    • String Based Enums
    • Nominal Typing
    • Stateful Functions
    • Currying
    • Type Instantiation
    • Lazy Object Literal Initialization
    • Classes are Useful
    • Avoid Export Default
    • Limit Property Setters
    • outFile caution
    • JQuery tips
    • static constructors
    • singleton pattern
    • Function parameters
    • Build Toggles
    • Barrel
    • Create Arrays
    • Typesafe Event Emitter
  • StyleGuide
  • TypeScript Compiler Internals
    • Program
    • AST
      • TIP: Visit Children
      • TIP: SyntaxKind enum
      • Trivia
    • Scanner
    • Parser
      • Parser Functions
    • Binder
      • Binder Functions
      • Binder Declarations
      • Binder Container
      • Binder SymbolTable
      • Binder Error Reporting
    • Checker
      • Checker Diagnostics
      • Checker Error Reporting
    • Emitter
      • Emitter Functions
      • Emitter SourceMaps
    • Contributing
Powered by GitBook
On this page
  • Налаштування
  • Теги HTML vs. Компоненти
  • Перевірка типу
  • Теги HTML
  • Функціональні компоненти
  • Компоненти Void-функцій (Void Function Components)
  • Компоненти класів
  • Підказка React JSX: інтерфейс для рендерингу
  • Підказка React JSX: Прийняти екземпляр компонента
  • Підказка React JSX: Прийміть компонент, який може впливати на пропси та рендеритися за допомогою JSX
  • Підказка React JSX: Загальні компоненти
  • Загальні функції
  • Підказка React: Строго типізовані посилання (Strongly Typed Refs)
  • Переконання типу (Type Assertions)
  • Значення за замовчуванням (Default Props)
  • Оголошення веб-компонента
Edit on GitHub
  1. JSX

React

PreviousJSXNextNon React JSX

Last updated 1 year ago

Налаштування

Наш . Ось основні моменти:

  • Використовуйте файли з розширенням .tsx (замість .ts).

  • Використовуйте "jsx": "react" у compilerOptions вашого tsconfig.json.

  • Встановіть визначення для JSX та React у вашому проекті: (npm i -D @types/react @types/react-dom).

  • Імпортуйте react у ваші .tsx файли (import * as React from "react").

Теги HTML vs. Компоненти

React може рендерити або HTML-теги (рядки), або React-компоненти. Виклик JavaScript для цих елементів відрізняється (React.createElement('div') проти React.createElement(MyComponent)). Це визначається за регістром першої літери. foo розглядається як HTML-тег, а Foo - як компонент.

Перевірка типу

Теги HTML

HTML-тег foo повинен мати тип JSX.IntrinsicElements.foo. Ці типи вже визначені для всіх основних тегів у файлі react-jsx.d.ts, який ви встановили під час інсталяції. Ось приклад вмісту цього файлу:

declare module JSX {
    interface IntrinsicElements {
        a: React.HTMLAttributes;
        abbr: React.HTMLAttributes;
        div: React.HTMLAttributes;
        span: React.HTMLAttributes;

        /// so on ...
    }
}

Функціональні компоненти

Ви можете визначати функціональні компоненти просто за допомогою інтерфейсу React.FunctionComponent. Наприклад:

type Props = {
  foo: string;
}
const MyComponent: React.FunctionComponent<Props> = (props) => {
    return <span>{props.foo}</span>
}

<MyComponent foo="bar" />

Компоненти Void-функцій (Void Function Components)

type Props = { 
  foo: string 
}
// OK now, in future, error
const FunctionComponent: React.FunctionComponent<Props> = ({ foo, children }: Props) => {
    return <div>{foo} {children}</div>; // OK
};
// Error now (children not support), in future, deprecated
const VoidFunctionComponent: React.VoidFunctionComponent<Props> = ({ foo, children }) => {
    return <div>{foo}{children}</div>; 
};

Компоненти класів

Типи компонентів перевіряються на основі властивостей props. Це моделюється після того, як JSX перетворюється, тобто атрибути стають props компонента.

Файл react.d.ts визначає клас React.Component<Props, State>, який ви повинні розширити у свому власному класі і надати свої власні інтерфейси Props і State. Нижче наведено приклад:

type Props = {
  foo: string;
}
class MyComponent extends React.Component<Props, {}> {
    render() {
        return <span>{this.props.foo}</span>
    }
}

<MyComponent foo="bar" />

Підказка React JSX: інтерфейс для рендерингу

Реакт може рендерити різні елементи, такі як JSX або string. Всі ці елементи об'єднані в типі React.ReactNode, тому використовуйте його, коли ви хочете приймати рендерні елементи, наприклад:

type Props = {
  header: React.ReactNode;
  body: React.ReactNode;
}
class MyComponent extends React.Component<Props, {}> {
    render() {
        return <div>
            {this.props.header}
            {this.props.body}
        </div>;
    }
}

<MyComponent header={<h1>Header</h1>} body={<i>body</i>} />

Підказка React JSX: Прийняти екземпляр компонента

Оголошення типу React.ReactElement<T> надається в типових визначеннях React для того, щоб ви могли вказати тип результату інстанціювання класового компонента <T/>, наприклад:

class MyAwesomeComponent extends React.Component {
  render() {
    return <div>Hello</div>;
  }
}

const foo: React.ReactElement<MyAwesomeComponent> = <MyAwesomeComponent />; // Okay
const bar: React.ReactElement<MyAwesomeComponent> = <NotMyAwesomeComponent />; // Error!

Звичайно, ви можете використовувати це як анотацію для аргументу функції, а також як prop member React компонента.

Підказка React JSX: Прийміть компонент, який може впливати на пропси та рендеритися за допомогою JSX

Тип React.Component<Props> об'єднує React.ComponentClass<P> та React.StatelessComponent<P>, тому ви можете приймати щось, що має тип Props і рендерити його за допомогою JSX, наприклад:

const X: React.Component<Props> = foo; // from somewhere

// Render X with some props:
<X {...props}/>;

Підказка React JSX: Загальні компоненти

Це працює саме так, як очікувається. Ось приклад:

/** A generic component */
type SelectProps<T> = { items: T[] }
class Select<T> extends React.Component<SelectProps<T>, any> { }

/** Usage */
const Form = () => <Select<string> items={['a','b']} />;

Загальні функції

Щось на кшталт наступного працює добре:

function foo<T>(x: T): T { return x; }

Однак, використання узагальненої функції зі стрілкою цього не зробить:

const foo = <T>(x: T) => x; // ERROR : unclosed `T` tag

Workaround: Використовуйте extends для параметра generic, щоб підказати компілятору, що це узагальнюючий параметр, наприклад:

const foo = <T extends unknown>(x: T) => x;

Підказка React: Строго типізовані посилання (Strongly Typed Refs)

Ви по суті ініціалізуєте змінну як об'єднання посилання (ref) і null, а потім ініціалізуєте її як зворотний виклик (callback), наприклад:

class Example extends React.Component {
  example() {
    // ... something
  }
  
  render() { return <div>Foo</div> }
}


class Use {
  exampleRef: Example | null = null; 
  
  render() {
    return <Example ref={exampleRef => this.exampleRef = exampleRef } />
  }
}

І те саме з посиланнями (ref) на вбудовані елементи, наприклад:

class FocusingInput extends React.Component<{ value: string, onChange: (value: string) => any }, {}>{
  input: HTMLInputElement | null = null;
    
  render() {
    return (
      <input
        ref={(input) => this.input = input}
        value={this.props.value}
        onChange={(e) => { this.props.onChange(e.target.value) } }
        />
      );
    }
    focus() {
      if (this.input != null) { this.input.focus() }
    }
}

Переконання типу (Type Assertions)

В TypeScript існує можливість використовувати переконання типу (type assertion), коли ви явно вказуєте компілятору, що ви знаєте більше про тип, ніж він сам.

Значення за замовчуванням (Default Props)

  • Компоненти зі станом та пропсами за замовчуванням: Ви можете вказати TypeScript, що властивість буде надана ззовні (React), використовуючи оператор null assertion (це не ідеальний варіант, але це найпростіше мінімальне рішення з мінімальною кількістю додаткового коду, яке я зміг придумати).

class Hello extends React.Component<{
  /**
   * @default 'TypeScript'
   */
  compiler?: string,
  framework: string
}> {
  static defaultProps = {
    compiler: 'TypeScript'
  }
  render() {
    const compiler = this.props.compiler!;
    return (
      <div>
        <div>{compiler}</div>
        <div>{this.props.framework}</div>
      </div>
    );
  }
}

ReactDOM.render(
  <Hello framework="React" />, // TypeScript React
  document.getElementById("root")
);
  • Для SFC компонентів зі значеннями за замовчуванням рекомендується використовувати прості патерни JavaScript, оскільки вони добре поєднуються з системою типів TypeScript. Ось приклад:

const Hello: React.SFC<{
  /**
   * @default 'TypeScript'
   */
  compiler?: string,
  framework: string
}> = ({
  compiler = 'TypeScript', // Default prop
  framework
}) => {
    return (
      <div>
        <div>{compiler}</div>
        <div>{framework}</div>
      </div>
    );
  };


ReactDOM.render(
  <Hello framework="React" />, // TypeScript React
  document.getElementById("root")
);

Оголошення веб-компонента

Якщо ви використовуєте веб-компонент, визначення типів React за замовчуванням (@types/react) не будуть знати про нього. Але ви можете легко оголосити його, наприклад, оголосити веб-компонент з назвою my-awesome-slider, який приймає пропси MyAwesomeSliderProps:

declare global {
  namespace JSX {
    interface IntrinsicElements {
      'my-awesome-slider': MyAwesomeSliderProps;
    }

    interface MyAwesomeSliderProps extends React.Attributes {
      name: string;
    }
  }
}

Тепер ви можете використовувати його в TSX:

<my-awesome-slider name='amazing'/>

Починаючи з , ви можете використовувати новий тип React.VoidFunctionComponent або React.VFC якщо ви хочете вказати, що компонент не приймає children. Це проміжне рішення до наступної основної версії описів типів (де VoidFunctionComponent буде застарілим, і за замовчуванням FunctionComponent не буде приймати дітей).

Використовуйте синтаксис as Foo для переконання типу, як ми рекомендуємо .

@types/react PR #46643
Безкоштовна серія відео на youtube про найкращі практики React / TypeScript
PRO Egghead курс з TypeScript та React
швидкий старт для браузера допоможе вам в розробці додатків React
DesignTSX
mentioned before