Help us understand the problem. What is going on with this article?

any警察24時👮‍♂️

これは TypeScript Advent Calendar 2019 22日目の代打記事です。

前回の投稿が好評だったため、ブラッシュアップ・CLIツール化し、any警察👮‍♂️を npm publish しました。READMEに記載したとおり、devDependencies に追加し、npx anycopを実行するとプロジェクトのany診断ができます。
anycop: https://www.npmjs.com/package/anycop

おことわり

これはanyを駆逐せよ、という目的で作ったものではありません。anyの使用状況が可視化されれば、課題点を把握し、チームで共有する事が出来るでしょう。時間のある時、型安全のカバレッジを向上する様な取り組みが出来れば、それはとても素晴らしい事です。any は悪者ではありません。TypeScript にこの仕様がなければ、今の JavaScript エコシステムに静的型付けを適用することは出来なかったでしょう。このツールで、any とより良い関係を築けたら幸いです。

変更点

前回投稿では「変数定義のany推論」に限定しましたが、パワーアップし、次の anyを検知する様になりました。

  • 変数宣言の any型推論
  • 関数引数の any型推論
  • BindingElementの any型推論
  • 関数の any戻り型推論
  • Arrow関数の any戻り型推論
  • AsExpression(as any アサーション)

TypeScriptプロジェクトにインストールし、実行した結果は以下の様になります。

image.png

変数宣言の any型推論

変数の明示的なany注釈はもちろん、any 推論も検知します。

function greet(message: any) {
  return message
}
// inferred "any" at VariableDeclaration
const message = greet('hello')

関数引数の any型推論

引数の明示的なany注釈はもちろん、参照している型定義が any 相当の場合も検知します。

// annotation of "any" at ParameterDeclaration (message)
function greet(message: any) {
  return message
}

BindingElementの any型推論

BindingElementで展開された参照が、any推論されている時も検知します。

type Props = { a: any, b: any }
// inferred "any" at BindingElement (a & b)
function greet({ a, b }: Props) {
  return { a, b }
}

関数の any戻り型推論

戻り型の明示的なany注釈はもちろん、any になってしまっている戻り型も検知します。

// inferred "any" at FunctionDeclReturn
function greet() {
  const message: any = 'hello'
  return message
}

Arrow関数の any戻り型推論

戻り型の明示的なany注釈はもちろん、any になってしまっている戻り型も検知します。

// inferred "any" at ArrowFunctionReturn
const abc = (param: string) => {
  switch (param) {
    case 'a':
      return true
    case 'b':
      return false
    case 'c':
      return '' as any
  }
}

AsExpression(as any アサーション)

asキーワードによるアサーションを検知します。

function greet() {
  return 'hello' as any // at AsExpression
}

anycop.config.js

プロジェクトルートにanycop.config.jsを設置することで、固有の設定ができます。errorThretholdはエラー報告の閾値です。「TypeSafe Coverage」の合計がこの数値を下回った場合、エラーを発生させることができます。インテグレーションツールへの導入などに活用してください。

module.exports = {
  targetDir: ".",
  errorThrethold: 0.2
}

検査項目増加による実装の変更点

ts.SourceFileはts.Nodeのルートノードであり、そこを起点に実行する再帰関数(visit関数)を見直しました。ts.Nodeはts.SyntaxKindを持ち合わせており、この SyntaxKind で処理を選り分けています。

function visit(node: ts.Node) {
  switch (node.kind) {
    case ts.SyntaxKind.VariableDeclaration:
      // 変数宣言であれば
      // ....処理
      break
    case ts.SyntaxKind.Parameter:
      // 引数であれば
      // ....処理
      break
    case ts.SyntaxKind.BindingElement:
      // BindingElementであれば
      // ....処理
      break
    case ts.SyntaxKind.FunctionDeclaration:
      // 関数宣言であれば
      // ....処理
      break
    case ts.SyntaxKind.ArrowFunction:
      // アロー関数宣言であれば
      // ....処理
      break
    case ts.SyntaxKind.AsExpression:
      // アサーションであれば
      // ....処理
      break
  }
  ts.forEachChild(node, visit)
}
visit(source)

ts.TypeChecker.getReturnTypeOfSignature

「うっかり関数戻り型がanyに落ちていた…」という検査を追加しました。ts.SignatureDeclarationは、関数宣言やアロー関数を指します。ts.TypeCheckerに備わったgetSignatureFromDeclaration関数とgetReturnTypeOfSignature関数を利用することで、flags を得ることができます。これをもってts.TypeFlags.Anyと一致しているかを判定し、Anyか否かを判定しています。

// ts.ArrowFunction / ts.FunctionDeclaration は
// ts.SignatureDeclaration のサブタイプ
// node: ts.SignatureDeclaration
const signature = checker.getSignatureFromDeclaration(node)
if (signature) {
  const { flags } = checker.getReturnTypeOfSignature(signature)
  return checkAny(source, node, flags, name)
}
Takepepe
Web Application Developer. interested in TypeScript AST.
http://design.dena.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした