有没有可能在不手动定义接口的情况下使def类型安全?

// With proper `Cat.meow(message: string)` declaration on `Cat`?
const Cat = function() {}
def(Cat, {
  meow: function(message: string) { console.log('meow ' + message) },
})

const cat = new Cat()
cat.meow('I want food')

// Implementation
function def<T>(klass: T, fns: { [k: string]: any }) {
  for (let k in fns) {
    Object.defineProperty(klass.prototype, k, { value: fns[k],
      enumerable: false, writable: true, configurable: true
    })
  }
}

另外,也许可以用一些巴别塔转换魔法来打字?

推荐答案

def()返回所需的构造函数,而不是试图改变其klass参数的类型,在概念上更清晰.尽管如此,通过将其设置为assertion function,从而将klass参数的类型缩小到具有适当construct signature的类型,is是可能的.

可能是这样的:

function def<A extends any[], T extends object, M extends Record<keyof M, Function>>(
    klass: (this: T, ...args: A) => void, fns: M & ThisType<T & M>
): asserts klass is typeof klass & (new (...args: A) => T & M) {
    for (let k in fns) {
        Object.defineProperty(klass.prototype, k, {
            value: fns[k],
            enumerable: false, writable: true, configurable: true
        })
    }
}

这解释了klass具有一些generic类型A的参数列表,并试图通过在klassfns属性中使用this parameterthe magic ThisType<T> utility type来提供有关在klassfns属性中使用this的合理有用的经验.这个 idea 是这样的,无论thisklass中,无论fns是什么类型,都将作为thisfns的自变量内上下文可用.

因此,以下代码将按预期进行编译和工作:

const Cat = function () { }
def(Cat, {
    meow(message: string) { console.log('meow ' + message) },
})
const cat = new Cat()
cat.meow('I want food') // meow I want food


const Dog = function (this: { name: string }, name: string) {
    this.name = name;
}
def(Dog, {
    bark() { console.log(this.name + " barks") }
})
const dog = new Dog("Fido");
console.log(dog.name); // Fido
dog.bark(); // Fido barks

Playground link to code

Typescript相关问答推荐

如何在不使用变量的情况下静态判断运算式的类型?

如何正确修复TypScript 4.7到4.8升级中的TS 2345编译错误

如何在函数参数中使用(或模仿)`success`的行为?

我应该使用什么类型的React表单onsubmit事件?

SortKey类型不起作用,尽管它使用的单个类型工作正常<>'

泛型函数即使没有提供类型

打印脚本丢失函数的泛型上下文

如何键入函数以只接受映射到其他一些特定类型的参数类型?

隐式键入脚本键映射使用

如何根据特定操作隐藏按钮

角效用函数的类型推断

是否可以针对联合类型验证类型属性名称?

AngularJS服务不会解析传入的Json响应到管道中的模型

是否可以判断某个类型是否已合并为内部类型?

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

在Cypress中,是否可以在不标识错误的情况下对元素调用.Click()方法?

在TypeScript中,如何通过一系列过滤器缩小类型?

如何在TypeScrip中使用数组作为字符串的封闭列表?

将带有额外id属性的Rust struct 展平回TypeScript单个对象,以返回wasm-bindgen函数

Typescript 确保通用对象不包含属性