概要
TypeScript Deep DiveのReact JSXをやってみる。
https://typescript-jp.gitbook.io/deep-dive/tsx/react
https://basarat.gitbooks.io/typescript/docs/jsx/react.html
Function Components(関数コンポーネント)
React.FunctionComponent
を使用して関数コンポーネントを定義する。
以降は、<script type="text/babel">
~</script>
を変更していくことにする。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Hello React!</title>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
<script type="text/babel">
type Props = {
foo: string;
}
const MyComponent: React.FunctionComponent<Props> = (props) => {
return <span>{props.foo}</span>
}
ReactDOM.render(<MyComponent foo="bar" />, document.getElementById('root'));
</script>
Class Components(クラスコンポーネント)
Componentクラスを継承して独自クラスを作成する。
index.d.tsからComponentクラス抜粋
// Base component for plain JS classes
// tslint:disable-next-line:no-empty-interface
interface Component<P = {}, S = {}, SS = any> extends ComponentLifecycle<P, S, SS> { }
class Component<P, S> {
// tslint won't let me format the sample code in a way that vscode likes it :(
/**
* If set, `this.context` will be set at runtime to the current value of the given Context.
*
* Usage:
*
* ```ts
* type MyContext = number
* const Ctx = React.createContext<MyContext>(0)
*
* class Foo extends React.Component {
* static contextType = Ctx
* context!: React.ContextType<typeof Ctx>
* render () {
* return <>My context's value: {this.context}</>;
* }
* }
* ```
*
* @see https://reactjs.org/docs/context.html#classcontexttype
*/
static contextType?: Context<any>;
/**
* If using the new style context, re-declare this in your class to be the
* `React.ContextType` of your `static contextType`.
*
* ```ts
* static contextType = MyContext
* context!: React.ContextType<typeof MyContext>
* ```
*
* @deprecated if used without a type annotation, or without static contextType
* @see https://reactjs.org/docs/legacy-context.html
*/
// TODO (TypeScript 3.0): unknown
context: any;
constructor(props: Readonly<P>);
/**
* @deprecated
* @see https://reactjs.org/docs/legacy-context.html
*/
constructor(props: P, 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: Readonly<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.
readonly props: Readonly<{ children?: ReactNode }> & Readonly<P>;
state: Readonly<S>;
/**
* @deprecated
* https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs
*/
refs: {
[key: string]: ReactInstance
};
}
独自クラスの実装例。
index.html
<!-- 省略 -->
<script type="text/babel">
type Props = {
foo: string;
}
class MyComponent extends React.Component<props, {}> {
render() {
return <span>{this.props.foo}</span>
}
}
ReactDOM.render(<MyComponent foo="bar" />, document.getElementById('root'));
</script>
React JSX Tip: Interface for renderable
React.ReactNode
型を使用すると、レンダリング可能なインターフェイスとして使える。
index.html
<!-- 省略 -->
<script type="text/babel">
type Props = {
header: React.ReactNode;
body: React.ReactNode;
}
class MyComponent extends React.Component<Props, {}> {
render() {
return <div>
{this.props.header}
{this.props.body}
</div>;
}
}
ReactDOM.render(<MyComponent header={<h1>Header</h1>} body={<i>body</i>} />, document.getElementById('root'));
</script>
React JSX Tip: Accept an instance of a Component
React.ReactElement<T>
コンポーネントのインスタンスにアノテーションを付けられる。const foo = <MyAwesomeComponent />;
で良い気もするけど、配列とかだと、ジェネリック型が効いてくるのかな?
index.html
<!-- 省略 -->
<script type="text/babel">
class MyAwesomeComponent extends React.Component<Props, {}> {
render() {
return <div>Hello</div>;
}
}
const foo: React.ReactElement<MyAwesomeComponent> = <MyAwesomeComponent />; // Okay
//const bar: React.ReactElement<MyAwesomeComponent> = <NotMyAwesomeComponent />; // Error
ReactDOM.render(foo, document.getElementById('root'));
</script>
続きは次回。
React JSX Tip: Accept a component that can act on props and be rendered using JSX
index.html
<!-- 省略 -->
<script type="text/babel">
// 次回
</script>
React JSX Tip: Generic components
index.html
<!-- 省略 -->
<script type="text/babel">
// 次回
</script>
Generic functions
index.html
<!-- 省略 -->
<script type="text/babel">
// 次回
</script>
React Tip: Strongly Typed Refs
index.html
<!-- 省略 -->
<script type="text/babel">
// 次回
</script>
Type Assertions
index.html
<!-- 省略 -->
<script type="text/babel">
// 次回
</script>
Default Props
index.html
<!-- 省略 -->
<script type="text/babel">
// 次回
</script>
感想
- 調べながらだと時間かかる
- 型がある世界は良い
- 日本語の情報少ない?
以上