Start Debugging

解決: google_fonts で The argument type 'TextTheme' can't be assigned to the parameter type 'TextTheme?' が出る

アプリは material_ui を import していますが、google_fonts 8.2.1 はまだ SDK の TextTheme を返します。google_fonts の移行が済むまでは、GoogleFonts.roboto のティアオフを使って TextTheme を自分で組み立ててください。

1 つのプログラムの中に TextTheme という名前の別々のクラスが 2 つ存在しています。アプリは package:material_ui/material_ui.dart を import しているので、ThemeData.textThemematerial_ui 側の TextTheme を期待します。一方、最新リリースの google_fonts 8.2.1 はまだ package:flutter/material.dart を import しているため、GoogleFonts.robotoTextTheme() は SDK 側の TextTheme を返します。Dart はこの 2 つを無関係な型として扱います。今日使える修正はこうです。...TextTheme() ヘルパーを呼ぶのをやめ、GoogleFonts.roboto のティアオフでスタイルごとにフォントを適用します。これは TextStyle を返し、この型は両方のコピーで共有されています。これはコンパイル時エラーなので、MaterialUiCompatibilityBridge では解決できません。

以下の内容はすべて Flutter 3.44.8 (Dart 3.12.2)、material_ui 1.2.0、cupertino_ui 1.0.2、google_fonts 8.2.1 で再現し、2026-09-11 時点の flutter/packages main ブランチにある google_fonts のソースと照らし合わせて確認しています。不一致の原因は SDK ではなくパッケージにあるため、同じエラーは 3.47 の stable 系列と master でも再現します。

アナライザーとコンパイラーが出力する内容

flutter analyze と IDE は短い形式を表示します。2 つの型名が同じなので、意味不明に見えます。

error • The argument type 'TextTheme' can't be assigned to the parameter type 'TextTheme?'.  • lib/main.dart:13:20 • argument_type_not_assignable

flutter runflutter buildflutter test で動くフロントエンドコンパイラーのほうが親切です。2 つの型に番号を振り、それぞれがどこにあるかを示してくれます。

lib/main.dart:13:47: Error: The argument type 'TextTheme/*1*/' can't be assigned to the parameter type 'TextTheme/*2*/?'.
 - 'TextTheme/*1*/' is from 'package:flutter/src/material/text_theme.dart' ('/opt/homebrew/share/flutter/packages/flutter/lib/src/material/text_theme.dart').
 - 'TextTheme/*2*/' is from 'package:material_ui/src/text_theme.dart' ('/Users/marius/.pub-cache/hosted/pub.dev/material_ui-1.2.0/lib/src/text_theme.dart').
        textTheme: GoogleFonts.robotoTextTheme(),
                                              ^

この 2 つ目のメッセージが診断そのものです。package:flutter/src/material/...package:material_ui/src/... の名前が出ていれば、このページで合っています。別の 2 つのライブラリの名前が出ている場合は、最後の「似ているが別のバグ」のセクションに進んでください。

TextTheme クラスが 2 つ存在する理由

Flutter 3.44 以降、Material と Cupertino は独立した material_ui パッケージと cupertino_ui パッケージとして提供されています。2026-08-12 に公開された material_ui 1.0.0 は、4 月に SDK 内で凍結された Material ライブラリのコピーです。再エクスポートではありません。material_ui/lib/src/text_theme.dart は独自の class TextTheme を宣言しており、ThemeDataThemeColorScheme も同様に独自に宣言しています。

Dart の型の同一性は、名前ではなく宣言しているライブラリで決まります。package:flutter/src/material/text_theme.dartTextThemepackage:material_ui/src/text_theme.dartTextTheme は同じフィールドと同じコードを持っていますが、どちらも他方のサブタイプではないため、互いに代入できません。

google_fonts 8.2.1 は material_ui が 1.0 に達する前の 2026-07-31 に公開されました。その lib/src/google_fonts_all_parts.dart には今も次の行があります。

// google_fonts 8.2.1, lib/src/google_fonts_all_parts.dart
import 'package:flutter/material.dart';

そして、生成された ...TextTheme ヘルパーはすべてこの import の上に作られています。

// google_fonts 8.2.1, lib/src/google_fonts_parts/part_r.dart (trimmed)
static TextTheme robotoTextTheme([TextTheme? textTheme]) {
  textTheme ??= ThemeData.light().textTheme;
  return TextTheme(
    displayLarge: roboto(textStyle: textTheme.displayLarge),
    // ...14 more styles
  );
}

パラメーターの型も戻り値の型も SDK の TextTheme です。ファイルが package:flutter/material.dart の代わりに material_ui を import するようになると (これはまさに dart fix --apply --code=migrate_design_widgets が行う変更です)、GoogleFonts.xxxTextTheme() を呼んでいる箇所はすべてコンパイルできなくなります。この問題は flutter/flutter#191067 で追跡されており、material_ui 1.0.0 のリリース翌日に起票されました。

最小の再現コード

# pubspec.yaml, Flutter 3.44.8
dependencies:
  flutter:
    sdk: flutter
  google_fonts: ^8.2.1
  material_ui: ^1.2.0
// Flutter 3.44.8, material_ui 1.2.0, google_fonts 8.2.1
import 'package:google_fonts/google_fonts.dart';
import 'package:material_ui/material_ui.dart';

void main() => runApp(const App());

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        textTheme: GoogleFonts.robotoTextTheme(), // error here
      ),
      home: const Scaffold(body: Center(child: Text('Hello'))),
    );
  }
}

import を package:flutter/material.dart に戻すとコンパイルが通ります。このエラーの報告の多くに「以前は動いていた」と書かれているのはこのためです。

MaterialUiCompatibilityBridge が役に立たない理由

material_ui 0.0.3 で追加されたブリッジは、誰もが最初に試すものであり、#191067 でメンテナーが最初に提案したのもこれでした。しかしこのエラーは解決せず、原理的に解決できません。ブリッジはウィジェットです。レガシーの ThemeLocalizations の InheritedWidget をツリーに挿入し、未移行のパッケージが実行時に Theme.of(context) を呼んだときに何かが見つかるようにします。対象になるのは、BuildContext から Material の状態を 読み取る 依存関係です。

google_fonts はツリーから何も読み取りません。公開 API から SDK の Material 型を 返し、その値は引数としてあなたのコードに流れ込みます。型チェッカーはウィジェットが 1 つも存在しない段階でそれを拒否します。flutter/flutter#191448 はこの制約を一般的な形で文書化しており、ファーストパーティの例として google_fonts のケースを最初に挙げています。コンパイルできない以上、ウィジェットのラッパーは関係ありません。

修正 1: ティアオフでスタイルごとにフォントを適用する (推奨)

TextStylepackage:flutter/painting.dart で宣言されています。これは SDK の一部であり、Material の両方のコピーで共有されています。GoogleFonts.roboto(...)TextStyle を返します。つまり置き換える必要があるのは、...TextTheme ヘルパーが代わりにやってくれている 15 行のループだけで、それは material_uiTextTheme に対して書けます。

// lib/theme/google_text_theme.dart
// Flutter 3.44.8, Dart 3.12.2, material_ui 1.2.0, google_fonts 8.2.1
import 'package:google_fonts/google_fonts.dart';
import 'package:material_ui/material_ui.dart';

/// Applies a Google Font to every style of a material_ui [TextTheme].
///
/// Pass a tear-off such as `GoogleFonts.roboto`. Only [TextStyle] crosses
/// the package boundary, and TextStyle lives in package:flutter/painting.dart,
/// which both copies of Material share.
TextTheme withGoogleFont(
  TextTheme base,
  TextStyle Function({TextStyle? textStyle}) font,
) {
  TextStyle? apply(TextStyle? style) =>
      style == null ? null : font(textStyle: style);

  return base.copyWith(
    displayLarge: apply(base.displayLarge),
    displayMedium: apply(base.displayMedium),
    displaySmall: apply(base.displaySmall),
    headlineLarge: apply(base.headlineLarge),
    headlineMedium: apply(base.headlineMedium),
    headlineSmall: apply(base.headlineSmall),
    titleLarge: apply(base.titleLarge),
    titleMedium: apply(base.titleMedium),
    titleSmall: apply(base.titleSmall),
    bodyLarge: apply(base.bodyLarge),
    bodyMedium: apply(base.bodyMedium),
    bodySmall: apply(base.bodySmall),
    labelLarge: apply(base.labelLarge),
    labelMedium: apply(base.labelMedium),
    labelSmall: apply(base.labelSmall),
  );
}

呼び出し側を短く保つ秘訣は font パラメーターの型にあります。生成されたフォントメソッドはすべて TextStyle Function({TextStyle? textStyle, Color? color, double? fontSize, ...}) というシグネチャを持っています。省略可能な名前付きパラメーターが多い関数型は、少ない関数型のサブタイプなので、GoogleFonts.robotoGoogleFonts.latoGoogleFonts.pangolin をそのまま渡せます。

あとは先にテーマを作り、そのテキストテーマを差し替えます。

// lib/main.dart
// Flutter 3.44.8, Dart 3.12.2, material_ui 1.2.0, google_fonts 8.2.1
import 'package:google_fonts/google_fonts.dart';
import 'package:material_ui/material_ui.dart';

import 'theme/google_text_theme.dart';

ThemeData buildTheme(Brightness brightness) {
  final base = ThemeData(
    brightness: brightness,
    colorSchemeSeed: Colors.indigo,
  );
  return base.copyWith(
    textTheme: withGoogleFont(base.textTheme, GoogleFonts.roboto),
  );
}

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: buildTheme(Brightness.light),
      darkTheme: buildTheme(Brightness.dark),
      home: const Scaffold(body: Center(child: Text('Hello'))),
    );
  }
}

これで flutter analyze はクリーンになり、ウィジェットテストでも出力が以前の GoogleFonts.robotoTextTheme() と一致することを確認できます。すべてのスタイルに fontFamily: 'Roboto_regular'fontFamilyFallback: ['Roboto'] が付きます。これは google_fonts が読み込んだバリアントに付ける名前です。

このバージョンには、置き換え前の呼び出しより優れている点が 1 つあります。引数なしの robotoTextTheme()ThemeData.light().textTheme から始まるため、ThemeData.dark().textTheme を渡さずに darkTheme で使い回すと、暗い背景に暗い文字が表示されていました。明るさごとに base.textTheme から派生させれば、構造上、色が正しくなります。上記のテストでは、ライトの bodyMedium はほぼ黒の Color(0xFF1B1B21) に、ダークの bodyMedium はほぼ白の Color(0xFFE4E1E9) に解決されます。

上流で移行が完了したら、このファイルを削除して GoogleFonts.robotoTextTheme(base.textTheme) に戻すだけで、テーマごとに 1 行の変更で済みます。

フォントファミリー名が実行時にしか分からない場合

ユーザーが設定画面でフォントを選ぶ場合、おそらく GoogleFonts.getTextTheme(name) を呼んでいたはずで、これにも同じ問題があります。TextStyle を返す getFont をラップしてください。

// Flutter 3.44.8, material_ui 1.2.0, google_fonts 8.2.1
TextTheme withGoogleFontNamed(TextTheme base, String family) =>
    withGoogleFont(
      base,
      ({TextStyle? textStyle}) =>
          GoogleFonts.getFont(family, textStyle: textStyle),
    );

これにはコストがあることを理解しておいてください。getFont はフォントファミリーを GoogleFonts.asMap() から探します。これは生成されたすべてのフォントメソッドを参照する const マップなので、コンパイラーは使われていないフォントをツリーシェイクできなくなります。修正 1 の直接のティアオフが参照するフォントは 1 つだけです。このサイズの差を狙っているのが flutter/packages#11433google_fonts_lite.dart エントリポイントで、2026-09-04 にマージされましたが、まだ公開されていません。getFont は実行時の名前が本当に必要な場合にだけ使ってください。

修正 2: 既存のレガシー TextTheme を境界で変換する

SDK の TextTheme が自分では制御できない場所から渡される場合 (たとえば今週は変更できない共有テーマパッケージなど)、フィールドごとに変換します。レガシーライブラリはプレフィックスと show 句を付けて import し、他の名前がファイルに漏れ込まないようにします。

// lib/theme/legacy_adapter.dart
// Flutter 3.44.8, Dart 3.12.2, material_ui 1.2.0, google_fonts 8.2.1
// Temporary: delete once google_fonts ships a material_ui release.
import 'package:flutter/material.dart' as legacy show TextTheme;
import 'package:material_ui/material_ui.dart';

extension LegacyTextThemeToMaterialUi on legacy.TextTheme {
  TextTheme toMaterialUi() => TextTheme(
        displayLarge: displayLarge,
        displayMedium: displayMedium,
        displaySmall: displaySmall,
        headlineLarge: headlineLarge,
        headlineMedium: headlineMedium,
        headlineSmall: headlineSmall,
        titleLarge: titleLarge,
        titleMedium: titleMedium,
        titleSmall: titleSmall,
        bodyLarge: bodyLarge,
        bodyMedium: bodyMedium,
        bodySmall: bodySmall,
        labelLarge: labelLarge,
        labelMedium: labelMedium,
        labelSmall: labelSmall,
      );
}
// Flutter 3.44.8, material_ui 1.2.0, google_fonts 8.2.1
final theme = ThemeData(
  textTheme: GoogleFonts.pangolinTextTheme().toMaterialUi(),
);

各フィールドが TextStyle なので、これはコンパイルが通ります。TextTheme でうまくいくのは、このクラスが 15 個のスタイルを詰めただけの単純な入れ物だからです。一般化はできません。#191448 では、メソッドが他の Material 型を引数に取る FloatingActionButtonLocation のような型では、同じアダプターの手法が 1 段深いところで失敗することが示されています。また、この方法は前述のライト専用のデフォルトもそのまま引き継ぎ、移行で取り除くはずだった SDK の Material の import を再び持ち込みます。そのため、コメントを付けて 1 つのファイルにとどめ、修正 1 を優先してください。

修正 3: google_fonts の移行を待つ

google_fonts 自体を移行するプルリクエストが 2 つあります。8 月 17 日に起票され #191067 にリンクされた flutter/packages#12489 と、エコシステム全体の flutter/flutter#191322 の一環として 9 月 9 日に起票された flutter/packages#12810 です。後者はパッケージの最小要件を Flutter 3.44 と Dart 3.12 に引き上げます。2026-09-11 時点では、どちらもマージされていません。どちらかがマージされれば、...TextTheme ヘルパーは material_ui の型を受け取って返すようになり、元の 1 行が再びコンパイルできるようになります。google_fonts の changelog を注視してください。

出荷するアプリにはおすすめしない待ち方が 2 つあります。

何らかの理由で修正 1 を使えない場合、正直な代替案は、google_fonts がリリースされるまで material_ui への移行を延期することです。SDK 内の Material ライブラリは凍結されていますが、3.47 でもまだ動作します。

落とし穴: ウェイトはまだテーマに入っていない

...TextTheme ヘルパーが常にやっていたことで、修正 1 もそのまま引き継いでいる点があります。ビルド時点の ThemeData.textTheme が保持しているのは色とフォントファミリーだけです。サイズとウェイトは Typography.englishLike から来ており、後で Theme.of がテーマをローカライズするときにマージされます。そのため、google_fontstitleMedium を見た時点ではウェイトが null で、regular のバリアントが選ばれ、スタイルには fontFamily: 'Roboto_regular' が付きます。実行時には Theme.of(context).textTheme.titleMediumRoboto_regularFontWeight.w500 に解決されるので、エンジンはウェイト 400 のファイルからウェイト 500 のスタイルを描画することになります。

タイトルやラベルに本物の medium ファイルが必要なら、フォントを適用する前にジオメトリーをマージしてください。

// Flutter 3.44.8, material_ui 1.2.0, google_fonts 8.2.1
final geometry = Typography.material2021().englishLike.merge(base.textTheme);
final textTheme = withGoogleFont(geometry, GoogleFonts.roboto);
// titleMedium -> fontFamily 'Roboto_500', fontWeight w500

どちらの結果もウィジェットテストで確認しました。トレードオフとして、英語向けのサイズが焼き込まれるため、中国語、日本語、韓国語で出荷する場合は、代わりにロケールごとにジオメトリー (Typography.material2021().tall または .dense) を選んでください。同じ理由で、TextTheme.apply(fontFamily: GoogleFonts.roboto().fontFamily) は罠です。ウェイトに関係なく、すべてのスタイルに 'Roboto_regular' を設定してしまいます。

似ているが別のバグ

関連記事

ソース

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< 戻る