You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular使用graphql-codegen报Object is of type unknown错误

问题根因

两个编译错误本质是GraphQL生成类型的可空性,与模板、分页管道要求的非空类型不匹配导致:

  • 第一个错误:graphql-codegen生成的BlogPostsQuery类型中,blogPost字段是可空联合类型Array<...>|null|undefined,且数组内部元素也允许为null,而paginate管道要求传入确定的非空集合类型Collection<unknown>,带null/undefined的联合类型无法直接赋值。
  • 第二个错误:因为blogPost数组元素可能为null,*ngFor遍历时TypeScript无法确定每个blog的具体类型,会将其推断为unknown,直接访问blog.image属性就会触发类型错误。另外原模板直接写blog.image.urls没有做空值判断,本身也存在运行时空指针风险。

修复方案

第一步:修改组件TS代码,提前处理空值输出明确类型

不要直接把整个Query对象传给模板处理,在组件逻辑层就过滤空值,输出类型明确的博客列表Observable,从根源解决类型不匹配问题。
修改后的组件代码:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
// 导入生成的类型,新增导入Maybe类型辅助
import { BlogPostsQuery, BlogPostsGQL } from '../graphql/graphql';

// 从生成的Query类型中直接推导单条博客的类型,无需重复手写
type BlogPost = Exclude<Exclude<BlogPostsQuery['blogPost'], null | undefined>[number], null | undefined>;

@Component({
  selector: 'app-blog',
  templateUrl: './blog.component.html',
  styleUrls: ['./blog.component.scss']
})
export class BlogComponent implements OnInit {
  public responsive: boolean = true;
  // 定义类型明确的博客列表流
  blogList$!: Observable<BlogPost[]>;
  modalIsActive!: boolean;
  values!: string;
  
  
  public config = {
    itemsPerPage: 1,
    // 分页默认页码从1开始,原配置写0会导致分页组件异常
    currentPage: parseInt(sessionStorage.getItem('blogPage') || '') || 1
  };

  constructor(
    private router: Router,
    private allBlogPostGQL: BlogPostsGQL
  ) {}

  ngOnInit() {
    this.blogList$ =  this.allBlogPostGQL
    .watch()
    .valueChanges
    .pipe(
      map(res => {
        const rawList = res.data.blogPost;
        // 过滤所有空值,通过类型谓词保证返回纯BlogPost类型的数组
        return (rawList || []).filter((blog): blog is BlogPost => !!blog);
      })
    );
  }


  onPageChange(number: number) {
    sessionStorage.setItem('blogPage', JSON.stringify(number));
    this.config.currentPage = number;
  }

  showMore(name: string) {
    this.router.navigate(['/blog', name]);
  }
}

第二步:修改模板代码,补全空判断、修正属性绑定

替换数据源为处理好的blogList$,补全可选链空判断,同时修正原逻辑中直接拼接数组到图片地址的错误:

<ng-container *ngFor="let blog of blogList$ | async | paginate: config">
    <img 
      class="image" 
      *ngIf="blog.image?.urls?.length" 
      [src]="'http://localhost:5002' + blog.image.urls[0]"
      alt="Placeholder image"
    >
</ng-container>

注意点:

  • 用Angular属性绑定[src]代替字符串插值拼接地址,避免变更检测异常
  • 生成类型中urls是字符串数组类型,不能直接把整个数组拼接到地址后,按需取对应下标的元素即可,常规封面图取第一个元素
  • 可选链?.会自动做空值判断,避免运行时访问null属性报错

(可选)优化codegen配置减少冗余空类型

如果你的GraphQL接口实际返回的博客列表、列表元素本身不会为null,可以修改codegen.yml配置,让生成的类型默认不带多余的null定义,从根源减少空判断代码:

generates:
  src/app/graphql/graphql.ts:
    plugins:
      - typescript
      - typescript-operations
      - typescript-apollo-angular
    config:
      arrayNullability: false # 数组本身不默认添加null类型
      nonArrayItemNullability: false # 数组元素不默认添加null类型

该配置必须和实际接口返回逻辑一致,不要为了消除编译错误随意修改,否则会引发运行时异常。


内容的提问来源于stack exchange,提问作者amin mohammadi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 13:18:31