React Bootstrap + TypeScript: Buttonのプロパティを動的に定める

[React Bootstrap](https://react-bootstrap.github.io/)は、Bootstrapのスタイルが適用されたコンポーネントをReactアプリケーションに組み込めるライブラリです。今年3月24日に正規バージョンv1.0.0がリリースされ、4月23日には1.0.1にアップデートされました。Bootstrapのみでは\<div\>などにやたらとクラスを詰め込んだDOM要素があふれます。それに対して、アプリケーションをReactのコンポーネントですっきりと組み立てられるのが利点です。

# ButtonコンポーネントのプロパティをJavaScript形式で定める
山盛りのクラスと`<div>`の入れ子を書くことなく、設定はタグの属性(プロパティ)で済ませられたりします。[`Button`](https://react-bootstrap.github.io/components/buttons/)コンポーネントのテキストやカラーテーマ(`variant`)、大きさ(`size`)なども、JavaScript形式(`js`ファイル)のコードでつぎのように動的に定められます(図001)。

```react:src/App.js
import React from 'react';
import { Container, Button } from 'react-bootstrap';

function App() {
	const buttonProps = {
		text: 'Button Text',
		variant: 'success',
		size: 'lg',
	};
	return (
		<div>
			<Container>
				<Button
					variant={buttonProps.variant}
					size={buttonProps.size}
				>
					{buttonProps.text}
				</Button>
			</Container>
		</div>
	);
}

export default App;
```

#### 図001■ButtonコンポーネントのプロパティをJavaScriptコードで定めた
![2006001_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128949/67897d3b-8b49-dc5e-17c7-5ba8e89a97bc.png)


# ButtonコンポーネントのプロパティをTypeScript形式で定める
前掲のJavaScriptコードを、TypeScript形式(`tsx`ファイル)にそのままコピーしてみましょう(TypeScript形式のひな形Reactアプリケーションのつくり方については「[Create React App + TypeScript: 関数コンポーネントにTypeScriptで型づけする](http://www.fumiononaka.com/Business/html5/FN2006001.html)」をお読みください)。たちまち、えらい剣幕で怒られます(図002)。

#### 図002■プロパティの指定が型に合わないというエラーメッセージ
![2006001_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128949/a2e98b9c-72f4-ebe6-6ae4-ed0c8f66826f.png)

プロパティ(`variant`と`size`)がとれる値(文字列)は決まっています。そのため、それら特定の[文字列が型](http://www.fumiononaka.com/Business/html5/FN1805001.html#sec08)として定められているからです。使う値を[型エイリアス](http://www.fumiononaka.com/Business/html5/FN1805001.html#sec07)`type`で宣言してしまえばよいでしょう。そのうえで、変数に`as`を用いて型変換(キャスト)します。

```react:src/App.tsx
type variant = 
	| 'primary'
	| 'secondary'
	| 'success'
	| 'danger'
	| 'warning'
	| 'info'
	| 'dark'
	| 'light'
	| 'link'
	| 'outline-primary'
	| 'outline-secondary'
	| 'outline-success'
	| 'outline-danger'
	| 'outline-warning'
	| 'outline-info'
	| 'outline-dark'
	| 'outline-light'
;
type size = 'sm' | 'lg';
function App() {
	/* ...[中略]... */
	return (
		<div className="App">
			<Container>
				{/* <Button
					variant={buttonProps.variant}
					size={buttonProps.size}
				> */}
				<Button
					variant={buttonProps.variant as variant}
					size={buttonProps.size as size}
				>
					{buttonProps.text}
				</Button>
			</Container>
		</div>
	);
}
```


# `ButtonProps`インタフェースを使う
エラーメッセージからソースを探ると、[`ButtonProps`](https://github.com/react-bootstrap/react-bootstrap/blob/master/types/components/Button.d.ts#L5)がインタフェースだとわかります。したがって、このインタフェースを`import`すれば、型づけできるということです。

ただし、ドットアクセス`ButtonProps.variant`で型を得ることはできません。つぎのような警告が示されるでしょう。型はブラケット参照`ButtonProps['variant']`で取り出さなければならないのです。

> 'ButtonProps.variant' にアクセスできません。'ButtonProps' は型で、名前空間ではありません。'ButtonProps["variant"]' で 'ButtonProps' のプロパティ 'variant' の型を取得するつもりでしたか?

インタフェース`ButtonProps`で型をキャストしたのが、つぎのコードです。サンプルをCodeSandbox「[React Boostrap + TypeScript: Dynamically changing Button properties](https://codesandbox.io/s/react-boostrap-typescript-dynamically-changing-button-properties-rqe8s)」に公開します。

```react:src/App.tsx
import React from 'react';
import {
	Container,
	Button,
	ButtonProps,
} from 'react-bootstrap';

function App() {
	const buttonProps = {
		text: 'Button Text',
		variant: 'success',
		size: 'lg',
	};
	return (
		<div className="App">
			<Container>
				<Button
					variant={buttonProps.variant as ButtonProps['variant']}
					size={buttonProps.size as ButtonProps['size']}
				>
					{buttonProps.text}
				</Button>
			</Container>
		</div>
	);
}

export default App;
```