ReactでcreateContextするときにTypeScriptのリントがエラーを吐く場合の対処法

追記 2019/12/27：
今現在は、以下の回避案2を使用すると、`Definition for rule '@typescript-eslint/no-object-literal-type-assertion' was not found`になります。

どうやら`@typescript-eslint`がv2で[破壊的変更が入った](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v2.0.0)ようです。

> Merged both no-angle-bracket-type-assertion and no-object-literal-type-assertion into one rule - consistent-type-assertions.

そういうことで、回避案２は[`@typescript-eslint/consistent-type-assertions`](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/consistent-type-assertions.md)を使うよう読み替えてください。

```
'@typescript-eslint/consistent-type-assertions': [
      'error',
      { assertionStyle: 'as', objectLiteralTypeAssertions: 'allow-as-parameter' },
    ],
```

============= 追記終わり =============

ReactでContext APIを使いたい場合、`createContext()`をする必要があります。

しかし、['@typescript-eslint'](https://github.com/typescript-eslint/typescript-eslint)や['TSLint'](https://palantir.github.io/tslint/)のrecommendedをデフォルトのリントルールとして使用している場合では、ここの型定義で少し詰まります。というか自分が詰まりました。TS力の弱さを認識する今日この頃です。

具体的には、「Type assertion on object literals is forbidden, use a type annotation instead.」として怒られます。

```typescript
interface ContextProps {
  value: string;
  fn: (string) => void;
}

const TabContext = React.createContext({} as ContextProps);
// ここの `{} as ContextProps` が 'Type assertion on object literals is forbidden, use a type annotation instead.' として怒られる。
```

## 回避案１：`Partial`を使用する

[`Partial<T>`型](https://tech-1natsu.hatenablog.com/entry/2018/07/07/233655)を利用することで、`<T>`のプロパティをすべてオプショナル（つまり`value?: string;`みたいなこと）にすることができる。

そのため、初期値が入力されていなくても問題なく通る。

```typescript
interface ContextProps {
  value: string;
  fn: (string) => void;
}

const Context = React.createContext<Partial<ContextProps>>();
```

当初はこの方針で進めていたのだが、すぐに問題に直面した。

`ContextProps`のすべてはオプショナルなため、値に`undefined`が許容されているとTSは理解するため、ContextのConsumer側ではそのハンドリングをする必要が出てくる。

```typescript
const { fn } = useContext(Context);
fn && fn('someThing');
// `fn`が存在していることを担保してからしか、`select`を実行できない
```

正直これは面倒くさいので、回避案２を採用する。

## 回避案２：'no-object-literal-type-assertion' のオプションを使用して回避する

まず回避する案１としては、'no-object-literal-type-assertion'ルール自体をオフにするがありますが、なるべく完全にオフにするのは避けたいものです。と思い探したところ、オプションが用意されていました。至れり尽くせり。

注意点として、['@typescript-eslint'](https://github.com/typescript-eslint/typescript-eslint)と['TSLint'](https://palantir.github.io/tslint/)では、オプション名が違ったりするので気を付けてください。['@typescript-eslint'](https://github.com/typescript-eslint/typescript-eslint)使ってるのに['TSLint'](https://palantir.github.io/tslint/)の書き方で修正しようとして、反映されず悩んだ過去があります。;(

```js
// For @typescript-eslint
'@typescript-eslint/no-object-literal-type-assertion': ['error', { allowAsParameter: true}],
// 特に、'error' のとこ、true とか書くと、後ろのオプションが認識されないので注意

// For TSLint
'no-object-literal-type-assertion': [true, { 'allow-arguments': true }],
```

これで晴れて、React の Context API を TypeScript と一緒に気持ちよく使うことができます。余談ですが、[`useContext`](https://reactjs.org/docs/hooks-reference.html#usecontext)はいいぞ。
### 参考

- [@typescript-eslint/no-object-literal-type-assertion](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-object-literal-type-assertion.md)
- [tslint/no-object-literal-type-assertion](https://palantir.github.io/tslint/rules/no-object-literal-type-assertion/)
- [stackoverflow - React createContext issue in Typescript?
](https://stackoverflow.com/questions/54577865/react-createcontext-issue-in-typescript)