Skip to content

Latest commit

Β 

History

History
469 lines (351 loc) Β· 18.6 KB

jsx.md

File metadata and controls

469 lines (351 loc) Β· 18.6 KB

λͺ©μ°¨ (Table of contents)

μ†Œκ°œ (Introduction)

κΈ°λ³Έ μ‚¬μš©λ²• (Basic usage)

as μ—°μ‚°μž (The as operator)

νƒ€μž… 검사 (Type Checking)

JSX κ²°κ³Ό νƒ€μž… (The JSX result type)

ν‘œν˜„μ‹ ν¬ν•¨ν•˜κΈ° (Embedding Expressions)

λ¦¬μ•‘νŠΈμ™€ ν†΅ν•©ν•˜κΈ° (React integration)

νŒ©ν† λ¦¬ ν•¨μˆ˜ (Factory Functions)

μ†Œκ°œ (Introduction)

β†₯ μœ„λ‘œ

JSXλŠ” λ‚΄μž₯ν˜• XML 같은 κ΅¬λ¬Έμž…λ‹ˆλ‹€. λ³€ν™˜μ˜ μ˜λ―ΈλŠ” κ΅¬ν˜„μ— 따라 λ‹€λ₯΄μ§€λ§Œ μœ νš¨ν•œ JavaScript둜 λ³€ν™˜λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€. JSXλŠ” React둜 큰 인기λ₯Ό μ–»μ—ˆμ§€λ§Œ, 이후 λ‹€λ₯Έ κ΅¬ν˜„λ„ λ“±μž₯ν–ˆμŠ΅λ‹ˆλ‹€. TypeScriptλŠ” μž„λ² λ”©, νƒ€μž… 검사, JSXλ₯Ό JavaScript둜 직접 μ»΄νŒŒμΌν•˜λŠ” 것을 μ§€μ›ν•©λ‹ˆλ‹€.

κΈ°λ³Έ μ‚¬μš©λ²• (Basic usage)

β†₯ μœ„λ‘œ

JSXλ₯Ό μ‚¬μš©ν•˜λ €λ©΄ λ‹€μŒ 두 가지 μž‘μ—…μ„ ν•΄μ•Ό ν•©λ‹ˆλ‹€.

  1. 파일 이름을 .tsx ν™•μž₯자둜 μ§€μ •ν•©λ‹ˆλ‹€.
  2. jsx μ˜΅μ…˜μ„ ν™œμ„±ν™”ν•©λ‹ˆλ‹€.

TypeScriptλŠ” preserve, react 및 react-nativeλΌλŠ” μ„Έ κ°€μ§€μ˜ JSX λͺ¨λ“œμ™€ ν•¨κ»˜ μ œκ³΅λ©λ‹ˆλ‹€. 이 λͺ¨λ“œλ“€μ€ 방좜 λ‹¨κ³„μ—μ„œλ§Œ 영ν–₯을 미치며, νƒ€μž… κ²€μ‚¬μ—λŠ” 영ν–₯을 받지 μ•ŠμŠ΅λ‹ˆλ‹€. preserve λͺ¨λ“œλŠ” λ‹€λ₯Έ λ³€ν™˜ 단계(예: Babel)에 μ‚¬μš©ν•˜λ„λ‘ 결과물의 일뢀λ₯Ό μœ μ§€ν•©λ‹ˆλ‹€. λ˜ν•œ 결과물은 .jsx 파일 ν™•μž₯자λ₯Ό κ°–μŠ΅λ‹ˆλ‹€. react λͺ¨λ“œλŠ” React.createElementλ₯Ό μƒμ„±ν•˜μ—¬, μ‚¬μš©ν•˜κΈ° 전에 JSX λ³€ν™˜μ΄ ν•„μš”ν•˜μ§€ μ•ŠμœΌλ©°, 결과물은 .js ν™•μž₯자λ₯Ό κ°–κ²Œ λ©λ‹ˆλ‹€. react-native λͺ¨λ“œλŠ” JSXλ₯Ό μœ μ§€ν•œλ‹€λŠ” 점은 preserve λͺ¨λ“œμ™€ λ™μΌν•˜μ§€λ§Œ, 결과물은 .js ν™•μž₯자λ₯Ό κ°–κ²Œ λœλ‹€λŠ” 점이 λ‹€λ¦…λ‹ˆλ‹€.

λͺ¨λ“œ μž…λ ₯ κ²°κ³Ό κ²°κ³Ό 파일 ν™•μž₯자
preserve <div /> <div /> .jsx
react <div /> React.createElement("div") .js
react-native <div /> <div /> .js

--jsx λͺ…령쀄 ν”Œλž˜κ·Έ λ˜λŠ” tsconfig.json 파일의 ν•΄λ‹Ή μ˜΅μ…˜μ„ μ‚¬μš©ν•˜μ—¬ λͺ¨λ“œλ₯Ό 지정할 수 μžˆμŠ΅λ‹ˆλ‹€.

*μ°Έκ³ : React JSXλ₯Ό 생성할 λ•Œ --jsxFactory μ˜΅μ…˜μœΌλ‘œ μ‚¬μš©ν•  JSX νŒ©ν† λ¦¬(JSX factory) ν•¨μˆ˜λ₯Ό 지정할 수 μžˆμŠ΅λ‹ˆλ‹€ (기본값은 React.createElement)

as μ—°μ‚°μž (The as operator)

β†₯ μœ„λ‘œ

νƒ€μž… 단언(type assertion)을 μ–΄λ–»κ²Œ μž‘μ„±ν•˜λŠ”μ§€ λ– μ˜¬λ € λ³ΌκΉŒμš”:

var foo = <foo>bar;

μœ„ μ½”λ“œλŠ” λ³€μˆ˜ barκ°€ foo νƒ€μž…μ΄λΌλŠ” 것을 λ‹¨μ–Έν•©λ‹ˆλ‹€. TypeScriptλŠ” κΊΎμ‡  κ΄„ν˜Έλ₯Ό μ‚¬μš©ν•΄ νƒ€μž…μ„ λ‹¨μ–Έν•˜κΈ° λ•Œλ¬Έμ—, JSX ꡬ문과 ν•¨κ»˜ μ‚¬μš©ν•  경우 νŠΉμ • 문법 해석에 λ¬Έμ œκ°€ 될 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. 결과적으둜 TypeScriptλŠ” .tsx νŒŒμΌμ—μ„œ ν™”μ‚΄ κ΄„ν˜Έλ₯Ό ν†΅ν•œ νƒ€μž… 단언을 ν—ˆμš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μœ„μ˜ ꡬ문은 .tsx νŒŒμΌμ—μ„œ μ‚¬μš©ν•  수 μ—†μœΌλ―€λ‘œ, asλΌλŠ” λŒ€μ²΄ μ—°μ‚°μžλ₯Ό 톡해 νƒ€μž… 단언을 ν•΄μ•Ό ν•©λ‹ˆλ‹€. μœ„μ˜ μ˜ˆμ‹œλŠ” as μ—°μ‚°μžλ‘œ μ‰½κ²Œ λ‹€μ‹œ μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

var foo = bar as foo;

as μ—°μ‚°μžλŠ” .ts와 .tsx 파일 λͺ¨λ‘ μ‚¬μš©ν•  수 있으며, κΊΎμ‡  κ΄„ν˜Έ ν˜•μ‹μ˜ 단언과 λ™μΌν•˜κ²Œ λ™μž‘ν•©λ‹ˆλ‹€.

νƒ€μž… 검사 (Type Checking)

β†₯ μœ„λ‘œ

JSX의 νƒ€μž… 검사λ₯Ό μ΄ν•΄ν•˜κΈ° μœ„ν•΄μ„ , λ¨Όμ € λ‚΄μž₯ μš”μ†Œμ™€ κ°’-기반 μš”μ†Œμ˜ 차이점에 λŒ€ν•΄ μ•Œμ•„μ•Ό ν•©λ‹ˆλ‹€. JSX ν‘œν˜„μ‹ <expr />μ—μ„œ expr은 ν™˜κ²½μ— λ‚΄μž₯된 μš”μ†Œ(예: DOM ν™˜κ²½μ˜ div λ˜λŠ” span) ν˜Ήμ€ μ‚¬μš©μžκ°€ λ§Œλ“  μ‚¬μš©μž μ •μ˜ μ»΄ν¬λ„ŒνŠΈλ₯Ό μ°Έμ‘°ν•  κ²ƒμž…λ‹ˆλ‹€. μ΄λŠ” λ‹€μŒκ³Ό 같은 두 가지 이유둜 μ€‘μš”ν•©λ‹ˆλ‹€:

  1. λ¦¬μ•‘νŠΈμ—μ„œ λ‚΄μž₯ μš”μ†ŒλŠ” React.createElement("div")κ³Ό 같은 λ¬Έμžμ—΄λ‘œ μƒμ„±λ˜λŠ” 반면, μ‚¬μš©μžκ°€ λ§Œλ“  μ»΄ν¬λ„ŒνŠΈλŠ” React.createElement("MyComponent")κ°€ μ•„λ‹™λ‹ˆλ‹€.
  2. JSX μš”μ†Œμ— μ „λ‹¬λ˜λŠ” μ†μ„±μ˜ νƒ€μž…μ€ λ‹€λ₯΄κ²Œ μ‘°νšŒλ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€. λ‚΄μž₯ μš”μ†Œμ˜ 속성은 λ‚΄μž¬μ μœΌλ‘œ μ•Œκ³  μžˆμ–΄μ•Ό ν•˜μ§€λ§Œ, μ»΄ν¬λ„ŒνŠΈλŠ” 각각 μžμ‹ μ˜ 속성 집합을 μ§€μ •ν•˜λ €κ³  ν•©λ‹ˆλ‹€.

TypeScriptλŠ” React와 λ™μΌν•œ κ·œμΉ™μ„ μ‚¬μš©ν•˜μ—¬ κ΅¬λ³„ν•©λ‹ˆλ‹€. λ‚΄μž₯ μš”μ†ŒλŠ” 항상 μ†Œλ¬Έμžλ‘œ μ‹œμž‘ν•˜κ³  κ°’-기반 μš”μ†ŒλŠ” 항상 λŒ€λ¬Έμžλ‘œ μ‹œμž‘ν•©λ‹ˆλ‹€.

λ‚΄μž₯ μš”μ†Œ (Intrinsic elements)

β†₯ μœ„λ‘œ

λ‚΄μž₯ μš”μ†ŒλŠ” 특수 μΈν„°νŽ˜μ΄μŠ€ JSX.IntrinsicElementsμ—μ„œ μ‘°νšŒλ©λ‹ˆλ‹€. 기본적으둜 이 μΈν„°νŽ˜μ΄μŠ€κ°€ μ§€μ •λ˜μ§€ μ•ŠμœΌλ©΄ κ·ΈλŒ€λ‘œ μ§„ν–‰λ˜μ–΄ λ‚΄μž₯ μš”μ†Œ νƒ€μž…μ€ κ²€μ‚¬λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 이 μΈν„°νŽ˜μ΄μŠ€κ°€ μžˆλŠ” 경우, λ‚΄μž₯ μš”μ†Œμ˜ 이름은 JSX.IntrinsicElements μΈν„°νŽ˜μ΄μŠ€μ˜ ν”„λ‘œνΌν‹°λ‘œ μ‘°νšŒλ©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄:

declare namespace JSX {
    interface IntrinsicElements {
        foo: any
    }
}

<foo />; // 성곡
<bar />; // 였λ₯˜

μœ„μ˜ μ˜ˆμ œμ—μ„œ <foo />λŠ” 잘 λ™μž‘ν•˜μ§€λ§Œ, <bar />λŠ” JSX.IntrinsicElements에 μ§€μ •λ˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— 였λ₯˜λ₯Ό μΌμœΌν‚΅λ‹ˆλ‹€.

μ°Έκ³ : λ‹€μŒκ³Ό 같이 JSX.IntrinsicElements에 catch-all λ¬Έμžμ—΄ μΈλ±μ„œλ₯Ό 지정할 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

declare namespace JSX {
    interface IntrinsicElements {
        [elemName: string]: any;
    }
}

κ°’-기반 μš”μ†Œ (Value-based elements)

β†₯ μœ„λ‘œ

κ°’-기반 μš”μ†ŒλŠ” ν•΄λ‹Ή μŠ€μ½”ν”„μ— μžˆλŠ” μ‹λ³„μžλ‘œ κ°„λ‹¨ν•˜κ²Œ μ‘°νšŒλ©λ‹ˆλ‹€.

import MyComponent from "./myComponent";

<MyComponent />; // 성곡
<SomeOtherComponent />; // 였λ₯˜

κ°’-기반 μš”μ†Œλ₯Ό μ •μ˜ν•˜λŠ”λ°μ—” λ‹€μŒμ˜ 두 가지 방법이 μžˆμŠ΅λ‹ˆλ‹€:

  1. ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈ (FC)
  2. ν΄λž˜μŠ€ν˜• μ»΄ν¬λ„ŒνŠΈ

이 두 가지 μœ ν˜•μ˜ κ°’-기반 μš”μ†ŒλŠ” JSX ν‘œν˜„μ‹μ—μ„œ μ„œλ‘œ ꡬ별할 수 μ—†μœΌλ―€λ‘œ, TSλŠ” κ³ΌλΆ€ν•˜ 해결을 μ‚¬μš©ν•˜μ—¬ λ¨Όμ € ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈ ν‘œν˜„μ‹μœΌλ‘œ ν•΄μ„ν•©λ‹ˆλ‹€. 이 과정이 μ„±κ³΅μ μœΌλ‘œ μ§„ν–‰λ˜λ©΄, TSλŠ” 이 선언을 ν‘œν˜„μ‹μœΌλ‘œ ν•΄μ„ν•©λ‹ˆλ‹€. ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈλ‘œ ν•΄μ„λ˜μ§€ μ•ŠλŠ”λ‹€λ©΄, TSλŠ” ν΄λž˜μŠ€ν˜• μ»΄ν¬λ„ŒνŠΈλ‘œ 해석을 μ‹œλ„ν•©λ‹ˆλ‹€. 이 과정도 μ‹€νŒ¨ν•  경우, TSλŠ” 였λ₯˜λ₯Ό λ³΄κ³ ν•©λ‹ˆλ‹€.

ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈ (Function Component)

β†₯ μœ„λ‘œ

μ΄λ¦„μ—μ„œ μ•Œ 수 μžˆλ“―, μ»΄ν¬λ„ŒνŠΈλŠ” 첫 번째 μΈμˆ˜κ°€ props 객체인 JavaScript ν•¨μˆ˜λ‘œ μ •μ˜λ©λ‹ˆλ‹€. TSλŠ” μ»΄ν¬λ„ŒνŠΈμ˜ λ°˜ν™˜ νƒ€μž…μ΄ JSX.Element에 ν• λ‹Ή κ°€λŠ₯ν•˜λ„λ‘ μš”κ΅¬ν•©λ‹ˆλ‹€.

interface FooProp {
  name: string;
  X: number;
  Y: number;
}

declare function AnotherComponent(prop: {name: string});
function ComponentFoo(prop: FooProp) {
  return <AnotherComponent name={prop.name} />;
}

const Button = (prop: {value: string}, context: { color: string }) => <button>

ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈλŠ” JavaScript ν•¨μˆ˜μ΄λ―€λ‘œ, ν•¨μˆ˜ μ˜€λ²„λ‘œλ“œ λ˜ν•œ μ‚¬μš© κ°€λŠ₯ν•©λ‹ˆλ‹€:

interface ClickableProps {
  children: JSX.Element[] | JSX.Element
}

interface HomeProps extends ClickableProps {
  home: JSX.Element;
}

interface SideProps extends ClickableProps {
  side: JSX.Element | string;
}

function MainButton(prop: HomeProps): JSX.Element;
function MainButton(prop: SideProps): JSX.Element {
  ...
}

μ°Έκ³ : ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈλŠ” 이전에 λ¬΄μƒνƒœ ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈ(SFC)둜 μ•Œλ €μ Έ μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ 졜근 λ²„μ „μ˜ λ¦¬μ•‘νŠΈμ—μ„  더 이상 ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈλ₯Ό λ¬΄μƒνƒœλ‘œ μ·¨κΈ‰ν•˜μ§€ μ•ŠμœΌλ©°, SFC νƒ€μž…κ³Ό κ·Έ 별칭인 StatelessComponent은 더 이상 μ‚¬μš©λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

ν΄λž˜μŠ€ν˜• μ»΄ν¬λ„ŒνŠΈ (Class Component)

β†₯ μœ„λ‘œ

ν΄λž˜μŠ€ν˜• μ»΄ν¬λ„ŒνŠΈμ˜ νƒ€μž…μ„ μ •μ˜ν•˜λŠ” 것은 κ°€λŠ₯ν•©λ‹ˆλ‹€. 이λ₯Ό μœ„ν•΄μ„  μš”μ†Œ 클래슀 νƒ€μž… κ³Ό μš”μ†Œ μΈμŠ€ν„΄μŠ€ νƒ€μž… μ΄λΌλŠ” μƒˆλ‘œμš΄ μš©μ–΄λ₯Ό 이해해야 ν•©λ‹ˆλ‹€.

<Expr />μ—μ„œ, μš”μ†Œ 클래슀 νƒ€μž… 은 Expr의 νƒ€μž…μž…λ‹ˆλ‹€. μœ„μ˜ μ˜ˆμ‹œμ—μ„œ MyComponentκ°€ ES6 클래슀라면 이 클래슀 νƒ€μž…μ€ 클래슀 μƒμ„±μžμ΄κ³  μ „μ—­μž…λ‹ˆλ‹€. MyComponentκ°€ νŒ©ν† λ¦¬ ν•¨μˆ˜λΌλ©΄, 클래슀 νƒ€μž…μ€ ν•΄λ‹Ή ν•¨μˆ˜μž…λ‹ˆλ‹€.

클래슀 νƒ€μž…μ΄ κ²°μ •λ˜λ©΄, μΈμŠ€ν„΄μŠ€ νƒ€μž…μ€ 클래슀 νƒ€μž…μ˜ μƒμ„±μž ν˜Ήμ€ 호좜 μ‹œκ·Έλ‹ˆμ²˜(μžˆλŠ” 것 쀑 μ–΄λŠ μͺ½μœΌλ‘œλ“ )에 μ˜ν•œ λ°˜ν™˜ νƒ€μž…μ„ κ²°ν•©ν•˜μ—¬ κ²°μ •λ©λ‹ˆλ‹€. λ”°λΌμ„œ ES6 클래슀의 경우, μΈμŠ€ν„΄μŠ€ νƒ€μž…μ€ ν•΄λ‹Ή 클래슀의 μΈμŠ€ν„΄μŠ€ νƒ€μž…μ΄ 되고, νŒ©ν† λ¦¬ ν•¨μˆ˜μ˜ κ²½μš°μ—” ν•΄λ‹Ή ν•¨μˆ˜λ‘œλΆ€ν„° λ°˜ν™˜λœ κ°’μ˜ νƒ€μž…μ΄ λ©λ‹ˆλ‹€.

class MyComponent {
  render() {}
}

// μƒμ„±μž μ‹œκ·Έλ‹ˆμ²˜ μ‚¬μš©
var myComponent = new MyComponent();

// μš”μ†Œ 클래슀 νƒ€μž… => MyComponent
// μš”μ†Œ μΈμŠ€ν„΄μŠ€ νƒ€μž… => { render: () => void }

function MyFactoryFunction() {
  return {
    render: () => {
    }
  }
}

// 호좜 μ‹œκ·Έλ‹ˆμ²˜ μ‚¬μš©
var myComponent = MyFactoryFunction();

// μš”μ†Œ 클래슀 νƒ€μž… => MyFactoryFunction
// μš”μ†Œ μΈμŠ€ν„΄μŠ€ νƒ€μž… => { render: () => void }

ν₯λ―Έλ‘­κ²Œλ„ μš”μ†Œ μΈμŠ€ν„΄μŠ€ νƒ€μž…μ€ JSX.ElementClass에 ν• λ‹Ή κ°€λŠ₯ν•΄μ•Ό ν•˜λ©°, 그렇지 μ•Šμ„ 경우 였λ₯˜λ₯Ό μΌμœΌν‚΅λ‹ˆλ‹€. 기본적으둜 JSX.ElementClassλŠ” {}μ΄μ§€λ§Œ, μ μ ˆν•œ μΈν„°νŽ˜μ΄μŠ€μ— μ ν•©ν•œ νƒ€μž…μœΌλ‘œλ§Œ JSXλ₯Ό μ‚¬μš©ν•˜λ„λ‘ μ œν•œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

declare namespace JSX {
  interface ElementClass {
    render: any;
  }
}

class MyComponent {
  render() {}
}
function MyFactoryFunction() {
  return { render: () => {} }
}

<MyComponent />; // 성곡
<MyFactoryFunction />; // 성곡

class NotAValidComponent {}
function NotAValidFactoryFunction() {
  return {};
}

<NotAValidComponent />; // 였λ₯˜
<NotAValidFactoryFunction />; // 였λ₯˜

속성 νƒ€μž… 검사 (Attribute type checking)

β†₯ μœ„λ‘œ

속성 νƒ€μž… 검사λ₯Ό μœ„ν•΄μ„  첫 번째둜 μš”μ†Œ 속성 νƒ€μž… 을 κ²°μ •ν•΄μ•Ό ν•©λ‹ˆλ‹€. μ΄λŠ” λ‚΄μž₯ μš”μ†Œμ™€ κ°’-기반 μš”μ†Œ 간에 μ•½κ°„ λ‹€λ₯Έ 점이 μžˆμŠ΅λ‹ˆλ‹€.

λ‚΄μž₯ μš”μ†Œμ˜ 경우, μš”μ†Œ 속성 νƒ€μž…μ€ JSX.IntrinsicElements의 ν”„λ‘œνΌν‹° νƒ€μž…κ³Ό λ™μΌν•©λ‹ˆλ‹€.

declare namespace JSX {
  interface IntrinsicElements {
    foo: { bar?: boolean }
  }
}

// 'foo'의 μš”μ†Œ 속성 νƒ€μž…μ€ '{bar?: boolean}'
<foo bar />;

κ°’-기반 μš”μ†Œμ˜ κ²½μš°μ—” 쑰금 더 λ³΅μž‘ν•©λ‹ˆλ‹€. 이전에 μš”μ†Œ μΈμŠ€ν„΄μŠ€ νƒ€μž… 의 ν”„λ‘œνΌν‹° νƒ€μž…μ— 따라 κ²°μ •λ©λ‹ˆλ‹€. μ‚¬μš©ν•  ν”„λ‘œνΌν‹°λŠ” JSX.ElementAttributesProperty에 따라 κ²°μ •λ©λ‹ˆλ‹€. μ΄λŠ” 단일 ν”„λ‘œνΌν‹°λ‘œ μ„ μ–Έλ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€. 이후 ν•΄λ‹Ή ν”„λ‘œνΌν‹° 이름을 μ‚¬μš©ν•©λ‹ˆλ‹€. TypeScript 2.8 λΆ€ν„° JSX.ElementAttributesPropertyκ°€ μ œκ³΅λ˜μ§€ μ•ŠμœΌλ©΄, 클래슀 μš”μ†Œμ˜ μƒμ„±μž λ˜λŠ” ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈμ˜ 첫 번째 λ§€κ°œλ³€μˆ˜ νƒ€μž…μ„ λŒ€μ‹  μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

declare namespace JSX {
  interface ElementAttributesProperty {
    props; // μ‚¬μš©ν•  ν”„λ‘œνΌν‹° 이름을 지정
  }
}

class MyComponent {
  // μš”μ†Œ μΈμŠ€ν„΄μŠ€ νƒ€μž…μ˜ ν”„λ‘œνΌν‹°λ₯Ό 지정
  props: {
    foo?: string;
  }
}

// 'MyComponent'의 μš”μ†Œ 속성 νƒ€μž…μ€ '{foo?: string}'
<MyComponent foo="bar" />

μš”μ†Œ 속성 νƒ€μž…μ€ JSXμ—μ„œ 속성 νƒ€μž…μ„ ν™•μΈν•˜λŠ”λ° μ‚¬μš©λ©λ‹ˆλ‹€. 선택적 ν˜Ήμ€ ν•„μˆ˜μ μΈ ν”„λ‘œνΌν‹°λ“€μ΄ μ§€μ›λ©λ‹ˆλ‹€.

declare namespace JSX {
  interface IntrinsicElements {
    foo: { requiredProp: string; optionalProp?: number }
  }
}

<foo requiredProp="bar" />; // 성곡
<foo requiredProp="bar" optionalProp={0} />; // 성곡
<foo />; // 였λ₯˜, requiredProp이 λˆ„λ½λ¨
<foo requiredProp={0} />; // 였λ₯˜, requiredProp은 λ¬Έμžμ—΄μ΄μ–΄μ•Ό 함
<foo requiredProp="bar" unknownProp />; // 였λ₯˜, unknownProp은 μ‘΄μž¬ν•˜μ§€ μ•ŠμŒ
<foo requiredProp="bar" some-unknown-prop />; // 성곡, 'some-unknown-prop'은 μœ νš¨ν•œ μ‹λ³„μžκ°€ μ•„λ‹ˆκΈ° λ•Œλ¬Έμ—

μ°Έκ³ : λ§Œμ•½ 속성 이름이 μœ νš¨ν•œ JavaScript μ‹λ³„μž(data-* 속성 λ“±)κ°€ μ•„λ‹Œ 경우, ν•΄λ‹Ή 이름을 μš”μ†Œ 속성 νƒ€μž…μ—μ„œ 찾을 수 없어도 였λ₯˜λ‘œ κ°„μ£Όν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μΆ”κ°€μ μœΌλ‘œ, JSX.IntrinsicAttributes μΈν„°νŽ˜μ΄μŠ€λŠ” 일반적으둜 μ»΄ν¬λ„ŒνŠΈμ˜ propsλ‚˜ 인수둜 μ‚¬μš©λ˜μ§€ μ•ŠλŠ” JSX ν”„λ ˆμž„μ›Œν¬λ₯Ό μœ„ν•œ 좔가적인 ν”„λ‘œνΌν‹°λ₯Ό 지정할 수 μžˆμŠ΅λ‹ˆλ‹€. - 예λ₯Ό λ“€λ©΄ React의 key. 더 λ‚˜μ•„κ°€μ„œ, JSX.IntrinsicClassAttributes<T> μ œλ„€λ¦­ νƒ€μž…μ„ μ‚¬μš©ν•˜μ—¬ ν΄λž˜μŠ€ν˜• μ»΄ν¬λ„ŒνŠΈμ— λŒ€ν•΄ λ™μΌν•œ μ’…λ₯˜μ˜ μΆ”κ°€ 속성을 지정할 수 μžˆμŠ΅λ‹ˆλ‹€ (ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈ μ œμ™Έν•˜κ³ ). 이 μœ ν˜•μ—μ„œ, μ œλ„€λ¦­μ˜ λ§€κ°œλ³€μˆ˜λŠ” 클래슀 μΈμŠ€ν„΄μŠ€ νƒ€μž…μ— ν•΄λ‹Ήν•©λ‹ˆλ‹€. React의 경우, μ΄λŠ” Ref<T> νƒ€μž…μ˜ ref 속성을 ν—ˆμš©ν•˜λŠ” 데에 μ“°μž…λ‹ˆλ‹€. μΌλ°˜μ μœΌλ‘œλŠ”, JSX ν”„λ ˆμž„μ›Œν¬ μ‚¬μš©μžκ°€ λͺ¨λ“  νƒœκ·Έμ— νŠΉμ • 속성을 μ œκ³΅ν•  ν•„μš”κ°€ μ—†λ‹€λ©΄, 이런 μΈν„°νŽ˜μ΄μŠ€μ˜ λͺ¨λ“  ν”„λ‘œνΌν‹°λŠ” 선택적이어야 ν•©λ‹ˆλ‹€.

μŠ€ν”„λ ˆλ“œ μ—°μ‚°μž λ˜ν•œ λ™μž‘ν•©λ‹ˆλ‹€:

var props = { requiredProp: "bar" };
<foo {...props} />; // 성곡

var badProps = {};
<foo {...badProps} />; // 였λ₯˜

μžμ‹ νƒ€μž… 검사 (Children Type Checking)

β†₯ μœ„λ‘œ

TypeScript 2.3λΆ€ν„°, TSλŠ” μžμ‹ 의 νƒ€μž… 검사λ₯Ό λ„μž…ν–ˆμŠ΅λ‹ˆλ‹€. μžμ‹ 은 μžμ‹ JSX ν‘œν˜„μ‹ 을 속성에 μ‚½μž…ν•˜λŠ” μš”μ†Œ 속성 νƒ€μž…μ˜ νŠΉμˆ˜ν•œ ν”„λ‘œνΌν‹°μž…λ‹ˆλ‹€. TSλŠ” JSX.ElementAttributesPropertyλ₯Ό μ‚¬μš©ν•΄ props λ₯Ό κ²°μ •ν•˜λŠ” 것과 μœ μ‚¬ν•˜κ²Œ, JSX.ElementChildrenAttributeλ₯Ό μ‚¬μš©ν•΄ ν•΄λ‹Ή props λ‚΄μ˜ μžμ‹ 의 이름을 κ²°μ •ν•©λ‹ˆλ‹€. JSX.ElementChildrenAttributeλŠ” 단일 ν”„λ‘œνΌν‹°λ‘œ μ„ μ–Έλ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

declare namespace JSX {
  interface ElementChildrenAttribute {
    children: {};  // μ‚¬μš©ν•  μžμ‹μ˜ 이름을 지정
  }
}
<div>
  <h1>Hello</h1>
</div>;

<div>
  <h1>Hello</h1>
  World
</div>;

const CustomComp = (props) => <div>{props.children}</div>
<CustomComp>
  <div>Hello World</div>
  {"This is just a JS expression..." + 1000}
</CustomComp>

λ‹€λ₯Έ μ†μ„±μ²˜λŸΌ μžμ‹ 의 νƒ€μž…λ„ 지정할 수 μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ React 타이핑 을 μ‚¬μš©ν•˜λŠ” 경우 κΈ°λ³Έ νƒ€μž…μ„ μ˜€λ²„λΌμ΄λ“œ ν•  κ²ƒμž…λ‹ˆλ‹€.

interface PropsType {
  children: JSX.Element
  name: string
}

class Component extends React.Component<PropsType, {}> {
  render() {
    return (
      <h2>
        {this.props.children}
      </h2>
    )
  }
}

// 성곡
<Component name="foo">
  <h1>Hello World</h1>
</Component>

// 였λ₯˜ : μžμ‹μ€ JSX.Element의 배열이 μ•„λ‹Œ JSX.Element νƒ€μž…μž…λ‹ˆλ‹€.
<Component name="bar">
  <h1>Hello World</h1>
  <h2>Hello World</h2>
</Component>

// 였λ₯˜ : μžμ‹μ€ JSX.Element의 λ°°μ—΄μ΄λ‚˜ λ¬Έμžμ—΄μ΄ μ•„λ‹Œ JSX.Element νƒ€μž…μž…λ‹ˆλ‹€.
<Component name="baz">
  <h1>Hello</h1>
  World
</Component>

JSX κ²°κ³Ό νƒ€μž… (The JSX result type)

β†₯ μœ„λ‘œ

기본적으둜 JSX ν‘œν˜„μ‹μ˜ 결과물은 any νƒ€μž…μž…λ‹ˆλ‹€. JSX.Element μΈν„°νŽ˜μ΄μŠ€λ₯Ό μˆ˜μ •ν•˜μ—¬ νŠΉμ •ν•œ νƒ€μž…μ„ 지정할 수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 이 μΈν„°νŽ˜μ΄μŠ€μ—μ„œλŠ” JSX의 μš”μ†Œ, 속성, μžμ‹μ— λŒ€ν•œ 정보λ₯Ό 검색할 수 μ—†μŠ΅λ‹ˆλ‹€. 이 μΈν„°νŽ˜μ΄μŠ€λŠ” λΈ”λž™λ°•μŠ€μž…λ‹ˆλ‹€.

ν‘œν˜„μ‹ ν¬ν•¨ν•˜κΈ° (Embedding Expressions)

β†₯ μœ„λ‘œ

JSXλŠ” μ€‘κ΄„ν˜Έ({ })둜 ν‘œν˜„μ‹μ„ 감싸 νƒœκ·Έ 사이에 ν‘œν˜„μ‹ μ‚¬μš©μ„ ν—ˆμš©ν•©λ‹ˆλ‹€.

var a = <div>
  {["foo", "bar"].map(i => <span>{i / 2}</span>)}
</div>

μœ„μ˜ μ½”λ“œλŠ” λ¬Έμžμ—΄μ„ 숫자둜 λ‚˜λˆŒ 수 μ—†μœΌλ―€λ‘œ 였λ₯˜λ₯Ό μΌμœΌν‚΅λ‹ˆλ‹€. preserve μ˜΅μ…˜μ„ μ‚¬μš©ν•  λ•Œ, κ²°κ³ΌλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€:

var a = <div>
  {["foo", "bar"].map(function (i) { return <span>{i / 2}</span>; })}
</div>

λ¦¬μ•‘νŠΈμ™€ ν†΅ν•©ν•˜κΈ° (React integration)

β†₯ μœ„λ‘œ

λ¦¬μ•‘νŠΈμ—μ„œ JSXλ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„  React 타이핑을 μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€. μ΄λŠ” λ¦¬μ•‘νŠΈλ₯Ό μ‚¬μš©ν•  수 μžˆλ„λ‘ JSX λ„€μž„μŠ€νŽ˜μ΄μŠ€λ₯Ό μ μ ˆν•˜κ²Œ μ •μ˜ν•©λ‹ˆλ‹€.

/// <reference path="react.d.ts" />

interface Props {
  foo: string;
}

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

<MyComponent foo="bar" />; // 성곡
<MyComponent foo={0} />; // 였λ₯˜

νŒ©ν† λ¦¬ ν•¨μˆ˜ (Factory Functions)

β†₯ μœ„λ‘œ

jsx: react 컴파일러 μ˜΅μ…˜μ—μ„œ μ‚¬μš©ν•˜λŠ” νŒ©ν† λ¦¬ ν•¨μˆ˜λŠ” 섀정이 κ°€λŠ₯ν•©λ‹ˆλ‹€. μ΄λŠ” jsxFactory λͺ…λ Ή 쀄 μ˜΅μ…˜μ„ μ‚¬μš©ν•˜κ±°λ‚˜ 인라인 @jsx 주석을 μ‚¬μš©ν•˜μ—¬ νŒŒμΌλ³„λ‘œ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ jsxFactory에 createElementλ₯Ό μ„€μ •ν–ˆλ‹€λ©΄, <div />λŠ” React.createElement("div") λŒ€μ‹  createElement("div")으둜 생성될 κ²ƒμž…λ‹ˆλ‹€.

주석 pragma 버전은 λ‹€μŒκ³Ό 같이 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€ (TypeScript 2.8 κΈ°μ€€):

import preact = require("preact");
/* @jsx preact.h */
const x = <div />;

μ΄λŠ” λ‹€μŒμ²˜λŸΌ μƒμ„±λ©λ‹ˆλ‹€:

const preact = require("preact");
const x = preact.h("div", null);

μ„ νƒλœ νŒ©ν† λ¦¬λŠ” μ „μ—­ λ„€μž„μŠ€νŽ˜μ΄μŠ€λ‘œ λŒμ•„κ°€κΈ° 전에 JSX λ„€μž„μŠ€νŽ˜μ΄μŠ€(νƒ€μž… 검사λ₯Ό μœ„ν•œ 정보)에도 영ν–₯을 λ―ΈμΉ©λ‹ˆλ‹€. νŒ©ν† λ¦¬κ°€ React.createElement(κΈ°λ³Έκ°’)둜 μ •μ˜λ˜μ–΄ μžˆλ‹€λ©΄, μ»΄νŒŒμΌλŸ¬λŠ” μ „μ—­ JSXλ₯Ό κ²€μ‚¬ν•˜κΈ° 전에 React.JSXλ₯Ό λ¨Όμ € 검사할 κ²ƒμž…λ‹ˆλ‹€. νŒ©ν† λ¦¬κ°€ h둜 μ •μ˜λ˜μ–΄ μžˆλ‹€λ©΄, μ»΄νŒŒμΌλŸ¬λŠ” μ „μ—­ JSXλ₯Ό κ²€μ‚¬ν•˜κΈ° 전에 h.JSXλ₯Ό 검사할 κ²ƒμž…λ‹ˆλ‹€.