一个关于typescript Omit泛型的问题

类型定义如下

type originType = "剪贴板" | "主动上传"
type Status = "上传成功" | "同步中"
export interface UploadInfo {
  addTime: number | Date
  finishTime: number | Date
  fileName: string
  url: string,
  mime: string,
  status: Status
  progress?: number
  origin: originType
}
function add(item: Omit<UploadInfo, "finishTime" | "status">) {
    const list = this.list.value;
    if (list.length > this.opt.max) {
      list.pop()
    }
    const uploadInfo: UploadInfo = {
      status: '上传成功',
      finishTime: new Date().getTime(),
      ...item,
    }
    list.unshift(uploadInfo);
  }

运行在使用add方法的时候不传入finishTime和status,因为在后面我给了默认值
但是有想要在主动调用的时候传入status值,ts类型提示不能复制给类型
image.png
image.png

阅读 2k
2 个回答

如果希望 finishTimestatus 可选,可以直接在接口中添加 ? 声明,就像 progress 那样。

如果只是希望参数部分属性可选,可以使用 Partial<UploadInfo> 让所有属性都可选。Omit 是去掉指定的属性,并非把这些属性变成可选。题中的错误是因为使用 Literal 对象会严格匹配类型但类型中又没有 status 属性造成的

const v = {
    addTime: 3,
    finishTime: 0,
    mime: "",
    fileName: "",
    url: "",
    status: "同步中" as Status,
    origin: "主动上传" as OriginType,
};

// 使用已有引用的对象时,只判断是否兼容,不严格匹配类型
add(v);    // <--- 这里不报错

// 直接使用 Literal 对象时会严格匹配类型
add({
    addTime: 3,
    mime: "",
    fileName: "",
    url: "",
    status: "同步中",  // <--- 这里会报错
    origin: "主动上传",
});

如果只是希望产生一个部分属性可选的新类型,可以这么计算

  1. 使用 Omit 去掉指定的属性 Keys,得到新类型 A
  2. 使用 PickKeys 指定的属性剥离出来,得到新类型 B
  3. 使用 Partial 把剥离出来的属性变成可选,得到新类型 B'
  4. 组合 AB',得到想要的结果

根据上面的描述可以定义一个新的工具类型

type SomePartial<Type, Keys extends keyof Type> = Omit<Type, Keys> & Partial<Pick<Type, Keys>>;

然后,使用 SomePartial 计算出来的类型应该就是你想要的

function add(item: SomePartial<UploadInfo, "finishTime" | "status">) {
    // TODO 
}

代码示例:TypeScript Playground

function add(item:Partial<UplaodInfo>)

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题