Upgrade to Pro — share decks privately, control downloads, hide ads and more …

推論された型の移植性エラーTS2742に挑む

 推論された型の移植性エラーTS2742に挑む

Avatar for teamLab

teamLab

May 25, 2025
Tweet

More Decks by teamLab

Other Decks in Programming

Transcript

  1. The inferred type of 'returnValue' cannot be named without a

    reference to ''../../middle-lib/node_modules/base-lib/dist/index.js'. This is likely not portable. A type annotation is necessary. ts(2742) 'returnValue' の推論された型には、'../../middle-lib/node_modules/base- lib/dist/index.js' への参照なしで名前を付けることはできません。これは、移植性がない可能性 があります。型の注釈が必要です。ts(2742) ? | 4 of 20
  2. base-libとmiddle-libのd.ts base-lib/index.d.ts middle-lib/index.d.ts base-lib に依存している base-lib index.d.ts index.js middle-lib index.d.ts

    index.js main index.ts export type SomeComplexType = { // (中身は余り関係無いが、単純すぎるとインライン化されるみたい) num: number; nest?: SomeComplexType; }; export declare const returnsInferredSomeComplexType: () => SomeComplexType; export declare const wrappedReturnsInferredSomeComplexType: () => import("base-lib").SomeComplexType; | 9 of 20
  3. mainパッケージでの問題 このコードをコンパイルしたとき、d.tsはどのように出力すべきか? base-lib index.d.ts index.js middle-lib index.d.ts index.js main index.ts

    index.d.ts mainパッケージで以下の様なコードを書いたとする。 import { wrappedReturnsInferredSomeComplexType } from "middle-lib"; export const mainValue = wrappedReturnsInferredSomeComplexType(); // ^| base-libの型SomeComplexTypeに推論されるが... import { wrappedReturnsInferredSomeComplexType } from "middle-lib"; export const mainValue: ???; | 10 of 20
  4. ダメな例 mainパッケージ基準の相対パスで指定 middle-libの内部ディレクトリを参照 -> node_modulesの構造はパッケージマネージャによって異なるのでNG 大まかには、hoistingするかどうかで変わる import { getBaseLibValue }

    from "middle-lib"; import type { SomeComplexType } from "../node_modules/middle-lib/node_modules/base-lib/index.js"; export const mainValue: SomeComplexType; import { getBaseLibValue } from "middle-lib"; import type { SomeComplexType } from "middle-lib/node_modules/base-lib/index.js"; export const mainValue: SomeComplexType; | 11 of 20
  5. これは…? 一見よさそうに見えるが、middle-lib --> base-libとmain --> base-libの指す先が同じとは限らな い 別のバージョンに依存していた場合は、実装と型が乖離して壊れる可能性がある main middle-lib

    base-lib@1 base-lib@2 -> 移植性がないとして TS2742 エラーを発生させる import { getBaseLibValue } from "middle-lib"; import type { SomeComplexType } from "base-lib"; export const mainValue: SomeComplexType; import { wrappedReturnsInferredSomeComplexType } from "middle-lib"; import type { SomeComplexType } from "???"; // 無理!!! export const mainValue: ???; // 無理!!! | 12 of 20
  6. ユーザ側(main)の対策 エラーの言うとおり、型注釈を明示的に書く … 型の注釈が必要です。ts(2742) これで解決!..🤔 型推論が便利なときは書きたくない… あと単に冗長 import { wrappedReturnsInferredSomeComplexType

    } from "ref"; export const returnValue: ReturnType< typeof wrappedReturnsInferredSomeComplexType > = wrappedReturnsInferredSomeComplexType(); const validator: () => { name: string } = createValidator( // ^ ここは書きたくないわけで z.object({ name: z.string() }), ); | 14 of 20
  7. ユーザ側(main)のworkaround tsconfigの declaration を false にする 有効なd.tsを出力できないからエラーになっているので、そもそも出力しなければエラーにならない 直接依存に追加してimportする import type

    {} from "base-lib" をmainのどこかに書く コンパイル対象のどこかに base-lib への参照があれば、それと同じ先に解決される ライブラリ側が依存しているバージョンと別のバージョンに解決してしまう可能性があるので要注意 TS5.5以上に上げてみる Consulting package.json Dependencies for Declaration File Generation TS5.4以前でTS2742エラーが発生している場合、偽陽性かもしれない 後述の対策をpnpm patch | 15 of 20