我有一个返回对象的函数.稍后,此对象将使用属性(例如$watch)进行扩展:

export default () => {
  const myObject = {
    property1: 'string1',
    property2: 1,
    init() {
      console.log('property1', this.property1)

      this.$watch('property1', (value) => { 
        console.log('property1 changed', value)
      })
    },
  }

  return myObject
}
interface OtherProps<T> {
  $watch: <K extends keyof T | string, V extends K extends keyof T ? T[K] : any>(
        property: K,
        callback: (newValue: V, oldValue: V) => void,
    ) => void;
  // ... other props
}

有没有办法把OtherProps的属性注入到myObject,这样TypeScript就不会说Property '$watch' does not exist on type ...了?

我设法以这种方式输入了它,但对于我的口味来说,它有点太冗长了,因为我必须单独输入定义:

type WithProps<T> = ThisType<T & OtherProps<T>>

type Test = WithProps<{
  property1: string
  property2: number
  init(): void
}>

export default () => {
  const myObject: Test = {
    property1: 'string1',
    property2: 1,
    init() {},
  }

  return myObject
}

我找到了this answer个,看起来很管用,但我很难根据我的情况来调整它.

推荐答案

如果您希望Typescript将generic类型参数推断为WithProps,则需要编写一个泛型帮助函数. 类型参数推断仅在调用泛型functions时发生;泛型types没有类似的行为. 这里有一种方法:

const withProps = <T,>(wp: T & ThisType<T & OtherProps<T>>) => wp;

这样,您可以编写const myObj = withProps({⋯}),而不是编写const myObj: WithProps<{⋯}> = {⋯},并且myObj的类型将以您想要的方式自动推断.我不知道您是否真的需要类型WithProps,所以我只是在上面内联了它.哦,你真的想要T & ThisType<T & OtherProps<T>>,而不是只有ThisType<T & OtherProps<T>>.如果没有T &,您将获得由the magical/intrinsic ThisType utility type提供的上下文this行为,但得到的对象类型将与T无关.

好吧,让我们试一试:

const x = () => withProps({
  property1: 'string1',
  property2: 1,
  init() {
    console.log('property1', this.property1)
    this.$watch('property1', (value) => {
      console.log('property1 changed', value)
    })
  },
});

看上go 不错.init()内部的this类型知道属性,也知道$watch.而推断的x的类型是

/* const x: () => {
    property1: string;
    property2: number;
    init(): void;
} & ThisType<{
    property1: string;
    property2: number;
    init(): void;
} & OtherProps<{
    property1: string;
    property2: number;
    init(): void;
}>> */

它按照指定的方式运行:

console.log(x().property1.toUpperCase()) // "STRING1"

Playground link to code

Typescript相关问答推荐

"@ clerker/nextjs/server没有名为clerkMiddleware的导入成员'

如何将http上下文附加到angular中翻译模块发送的请求

带有微前端的动态React路由问题

TS不推断类型在条件判断后具有属性'

如何为父类构造函数中的修饰属性赋值?

数组文字中对象的从键开始枚举

类型脚本类型字段组合

在TypeScrip中分配回调时,参数的分配方向与回调本身相反.为什么会这样呢?

保护函数调用,以便深度嵌套的对象具有必须与同级属性函数cargument的类型匹配的键

避免混淆两种不同的ID类型

我怎样才能正确地输入这个函数,使它在没有提供正确的参数时出错

与toast.error一起react 中的Async TUNK错误消息

使用ngfor循环时,数据未绑定到表

如何在Angular /字体中访问API响应的子元素?

VUE 3类型';字符串';不可分配给类型';参考<;字符串&>

如何从抽象类的静态方法创建子类的实例?

我可以将一个类型数组映射到TypeScrip中的另一个类型数组吗?

有没有一种方法可以防止我的组件包在其中安装样式组件'; node 模块中的s目录

Typescript 是否可以区分泛型参数 void?

Mongodb TypeError:类继承 events_1.EventEmitter 不是对象或 null