型強化の呪文。noImplicitAny
上記記事をたまたま読んで目にした呪文。noImplicitAny。
Over time, they reached the point of enabling advanced compiler options, such as –noImplicitAny to prevent the compiler from inferring an any type.
advancedってすごいな。なるほど。やってみましょう。また、ドキュメントを見ると、strictNullChecksなるものも。
// tsconfig.json { "compilerOptions": { "noImplicitAny": true, "strictNullChecks": true, "module": "commonjs", "target": "es5", "jsx": "react", "lib": ["es6", "dom"], "types": ["webpack-env", "jest"] } }
ちょいちょい「暗黙のany」を怒るエラーがでてきました。たとえばこんなの。
export class Counter extends React.Component<{}, { counter: number }> { constructor(props) { super(props); this.state = { counter: 0 }; } // 省略 }
このconstructorの引数に型が無い。直すと以下。
export class Counter extends React.Component<{}, { counter: number }> { constructor(props: {}) { super(props); this.state = { counter: 0 }; } // 省略 }
結構な箇所を直したら、noImplicitAny=trueでもOKになった。明示的なanyはOK。
import { handleActions } from 'redux-actions'; import { LOCATION_CHANGE } from 'react-router-redux'; import { matchPath } from 'react-router'; import { Map } from 'immutable'; const decodeName = (pathname: string) => { const m = matchPath<{ name?: string; }>(pathname, { path: '/player/:name' }); if (m) { return { ...m.params, name: m.params.name }; } return {}; }; type AppState = Map<string, any>; export const app = handleActions<AppState, any>( { // 省略 MOVE_TO: (state: AppState, { payload: { name } }) => { return state.merge({ name }); }, [LOCATION_CHANGE]: (state: AppState, { payload: { pathname } }) => state.merge(decodeName(pathname)), }, Map({}), );
Redux ActionsのhandleActionsの型引数の2番目には、Payloadがきます。でもこれはMOVE_TOのときには、{ name } だし、LOCATION_CHANGEのときは{ pathname }だから、anyで受けたかった。で、明示しているからOKだった。
React RouterのmatchPathは面白くて、型引数にExpressスタイルのURL分解パラメータをあらかじめ型として持つ。'/player/:name'の結果を{ name?: string; }で受けたために、m.params.nameという取り方ができるようになる。
strictNullChecksは結構直すの簡単ながら、なるほどそこでnullの可能性あるかと気がつかしてくれる。とても有用。
結論
noImplicitAnyはtrueにするのが正義。strictNullChecksはさらにもっと実利がある。ほか、noImplicitThisやalwaysStrictも含めて、単にstrict=trueにすれば一番厳しい。